4342 lines
92 KiB
C++
4342 lines
92 KiB
C++
// 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.39 $
|
|
//
|
|
|
|
#ifndef __DEELX_REGEXP__H__
|
|
#define __DEELX_REGEXP__H__
|
|
|
|
#include <memory.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
//
|
|
// Data Reference
|
|
//
|
|
template <class ELT> 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 <ELT> &) const;
|
|
int CompareNoCase(const CBufferRefT <ELT> &) 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 <class ELT> CBufferRefT <ELT> :: CBufferRefT(const ELT * pcsz, int length)
|
|
{
|
|
m_pRef = pcsz;
|
|
m_nSize = length;
|
|
}
|
|
|
|
template <class ELT> CBufferRefT <ELT> :: CBufferRefT(const ELT * pcsz)
|
|
{
|
|
m_pRef = pcsz;
|
|
m_nSize = 0;
|
|
|
|
if(pcsz != 0) while(m_pRef[m_nSize] != 0) m_nSize ++;
|
|
}
|
|
|
|
template <class ELT> int CBufferRefT <ELT> :: nCompare(const ELT * pcsz) const
|
|
{
|
|
for(int i=0; i<m_nSize; i++)
|
|
{
|
|
if(m_pRef[i] != pcsz[i])
|
|
return m_pRef[i] - pcsz[i];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <class ELT> int CBufferRefT <ELT> :: nCompareNoCase(const ELT * pcsz) const
|
|
{
|
|
for(int i=0; i<m_nSize; i++)
|
|
{
|
|
if(m_pRef[i] != pcsz[i])
|
|
{
|
|
if(toupper((int)m_pRef[i]) != toupper((int)pcsz[i]))
|
|
return m_pRef[i] - pcsz[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <class ELT> inline int CBufferRefT <ELT> :: Compare(const ELT * pcsz) const
|
|
{
|
|
return nCompare(pcsz) ? 1 : (int)pcsz[m_nSize];
|
|
}
|
|
|
|
template <class ELT> inline int CBufferRefT <ELT> :: CompareNoCase(const ELT * pcsz) const
|
|
{
|
|
return nCompareNoCase(pcsz) ? 1 : (int)pcsz[m_nSize];
|
|
}
|
|
|
|
template <class ELT> inline int CBufferRefT <ELT> :: Compare(const CBufferRefT <ELT> & cref) const
|
|
{
|
|
return m_nSize == cref.m_nSize ? nCompare(cref.GetBuffer()) : 1;
|
|
}
|
|
|
|
template <class ELT> inline int CBufferRefT <ELT> :: CompareNoCase(const CBufferRefT <ELT> & cref) const
|
|
{
|
|
return m_nSize == cref.m_nSize ? nCompareNoCase(cref.GetBuffer()) : 1;
|
|
}
|
|
|
|
template <class ELT> inline ELT CBufferRefT <ELT> :: At(int nIndex, ELT def) const
|
|
{
|
|
return nIndex >= m_nSize ? def : m_pRef[nIndex];
|
|
}
|
|
|
|
template <class ELT> inline ELT CBufferRefT <ELT> :: operator [] (int nIndex) const
|
|
{
|
|
return nIndex >= m_nSize ? 0 : m_pRef[nIndex];
|
|
}
|
|
|
|
template <class ELT> const ELT * CBufferRefT <ELT> :: GetBuffer() const
|
|
{
|
|
static const ELT _def[] = {0}; return m_pRef ? m_pRef : _def;
|
|
}
|
|
|
|
template <class ELT> inline int CBufferRefT <ELT> :: GetSize() const
|
|
{
|
|
return m_nSize;
|
|
}
|
|
|
|
template <class ELT> CBufferRefT <ELT> :: ~CBufferRefT()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Data Buffer
|
|
//
|
|
template <class ELT> class CBufferT : public CBufferRefT <ELT>
|
|
{
|
|
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 <class ELT> CBufferT <ELT> :: CBufferT(const ELT * pcsz, int length) : CBufferRefT <ELT> (0, length)
|
|
{
|
|
m_nMaxLength = CBufferRefT <ELT> :: m_nSize + 1;
|
|
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) malloc(sizeof(ELT) * m_nMaxLength);
|
|
memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> :: m_nSize);
|
|
m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
|
|
}
|
|
|
|
template <class ELT> CBufferT <ELT> :: CBufferT(const ELT * pcsz) : CBufferRefT <ELT> (pcsz)
|
|
{
|
|
m_nMaxLength = CBufferRefT <ELT> :: m_nSize + 1;
|
|
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) malloc(sizeof(ELT) * m_nMaxLength);
|
|
memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> :: m_nSize);
|
|
m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
|
|
}
|
|
|
|
template <class ELT> CBufferT <ELT> :: CBufferT() : CBufferRefT <ELT> (0, 0)
|
|
{
|
|
m_nMaxLength = 0;
|
|
m_pBuffer = 0;
|
|
}
|
|
|
|
template <class ELT> inline ELT & CBufferT <ELT> :: operator [] (int nIndex)
|
|
{
|
|
return m_pBuffer[nIndex];
|
|
}
|
|
|
|
template <class ELT> inline const ELT & CBufferT <ELT> :: operator [] (int nIndex) const
|
|
{
|
|
return m_pBuffer[nIndex];
|
|
}
|
|
|
|
template <class ELT> void CBufferT <ELT> :: Append(const ELT * pcsz, int length, int eol)
|
|
{
|
|
int nNewLength = m_nMaxLength;
|
|
|
|
// Check length
|
|
if(nNewLength < 8)
|
|
nNewLength = 8;
|
|
|
|
if(CBufferRefT <ELT> :: m_nSize + length + eol > nNewLength)
|
|
nNewLength *= 2;
|
|
|
|
if(CBufferRefT <ELT> :: m_nSize + length + eol > nNewLength)
|
|
{
|
|
nNewLength = CBufferRefT <ELT> :: m_nSize + length + eol + 11;
|
|
nNewLength -= nNewLength % 8;
|
|
}
|
|
|
|
// Realloc
|
|
if(nNewLength > m_nMaxLength)
|
|
{
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
|
|
m_nMaxLength = nNewLength;
|
|
}
|
|
|
|
// Append
|
|
memcpy(m_pBuffer + CBufferRefT <ELT> :: m_nSize, pcsz, sizeof(ELT) * length);
|
|
CBufferRefT <ELT> :: m_nSize += length;
|
|
|
|
if(eol > 0) m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
|
|
}
|
|
|
|
template <class ELT> inline void CBufferT <ELT> :: Append(ELT el, int eol)
|
|
{
|
|
Append(&el, 1, eol);
|
|
}
|
|
|
|
template <class ELT> void CBufferT <ELT> :: Push(ELT el)
|
|
{
|
|
// Realloc
|
|
if(CBufferRefT <ELT> :: m_nSize >= m_nMaxLength)
|
|
{
|
|
int nNewLength = m_nMaxLength * 2;
|
|
if( nNewLength < 8 ) nNewLength = 8;
|
|
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
|
|
m_nMaxLength = nNewLength;
|
|
}
|
|
|
|
// Append
|
|
m_pBuffer[CBufferRefT <ELT> :: m_nSize++] = el;
|
|
}
|
|
|
|
template <class ELT> inline int CBufferT <ELT> :: Pop(ELT & el)
|
|
{
|
|
if(CBufferRefT <ELT> :: m_nSize > 0)
|
|
{
|
|
el = m_pBuffer[--CBufferRefT <ELT> :: m_nSize];
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
template <class ELT> inline int CBufferT <ELT> :: Peek(ELT & el) const
|
|
{
|
|
if(CBufferRefT <ELT> :: m_nSize > 0)
|
|
{
|
|
el = m_pBuffer[CBufferRefT <ELT> :: m_nSize - 1];
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
template <class ELT> const ELT * CBufferT <ELT> :: GetBuffer() const
|
|
{
|
|
static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : _def;
|
|
}
|
|
|
|
template <class ELT> ELT * CBufferT <ELT> :: GetBuffer()
|
|
{
|
|
static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : (ELT *)_def;
|
|
}
|
|
|
|
template <class ELT> ELT * CBufferT <ELT> :: Detach()
|
|
{
|
|
ELT * pBuffer = m_pBuffer;
|
|
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = 0;
|
|
CBufferRefT <ELT> :: m_nSize = m_nMaxLength = 0;
|
|
|
|
return pBuffer;
|
|
}
|
|
|
|
template <class ELT> void CBufferT <ELT> :: Release()
|
|
{
|
|
ELT * pBuffer = Detach();
|
|
|
|
if(pBuffer != 0) free(pBuffer);
|
|
}
|
|
|
|
template <class ELT> void CBufferT <ELT> :: 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;
|
|
}
|
|
|
|
CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
|
|
m_nMaxLength = nNewLength;
|
|
}
|
|
|
|
// size
|
|
if( CBufferRefT <ELT> :: m_nSize < nNewSize )
|
|
{
|
|
memset(m_pBuffer + CBufferRefT <ELT> :: m_nSize, fill, sizeof(ELT) * (nNewSize - CBufferRefT <ELT> :: m_nSize));
|
|
CBufferRefT <ELT> :: m_nSize = nNewSize;
|
|
}
|
|
}
|
|
|
|
template <class ELT> inline void CBufferT <ELT> :: Restore(int size)
|
|
{
|
|
CBufferRefT <ELT> :: m_nSize = size;
|
|
}
|
|
|
|
template <class ELT> CBufferT <ELT> :: ~CBufferT()
|
|
{
|
|
if(m_pBuffer != 0) free(m_pBuffer);
|
|
}
|
|
|
|
//
|
|
// Context
|
|
//
|
|
class CContext
|
|
{
|
|
public:
|
|
CBufferT <int> m_stack;
|
|
CBufferT <int> 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 <int x> class CAlternativeElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CAlternativeElxT();
|
|
|
|
public:
|
|
CBufferT <ElxInterface *> m_elxlist;
|
|
};
|
|
|
|
typedef CAlternativeElxT <0> CAlternativeElx;
|
|
|
|
//
|
|
// Assert
|
|
//
|
|
template <int x> 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 CHART> 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 <CHART> m_szNamed;
|
|
};
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
template <class CHART> CBackrefElxT <CHART> :: CBackrefElxT(int nnumber, int brightleft, int bignorecase)
|
|
{
|
|
m_nnumber = nnumber;
|
|
m_brightleft = brightleft;
|
|
m_bignorecase = bignorecase;
|
|
}
|
|
|
|
template <class CHART> int CBackrefElxT <CHART> :: 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 <CHART> 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 <class CHART> int CBackrefElxT <CHART> :: 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_FILE_END_N, // end of whole text, or before newline at the end
|
|
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 CHART> 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 <class CHART> CBoundaryElxT <CHART> :: CBoundaryElxT(int ntype, int byes)
|
|
{
|
|
m_ntype = ntype;
|
|
m_byes = byes;
|
|
}
|
|
|
|
template <class CHART> int CBoundaryElxT <CHART> :: 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_FILE_END_N:
|
|
bsucc = (npos >= tlen) || (pcsz[tlen-1] == RCHART('\n') && (npos == tlen-1 || (pcsz[tlen-2] == RCHART('\r') && npos == tlen-2)));
|
|
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 m_byes ? bsucc : ! bsucc;
|
|
}
|
|
|
|
template <class CHART> int CBoundaryElxT <CHART> :: MatchNext(CContext *) const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
template <class CHART> inline int CBoundaryElxT <CHART> :: 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 CHART> class CBracketElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CBracketElxT(int nnumber, int bright);
|
|
int CheckCaptureIndex(int & index, CContext * pContext) const;
|
|
|
|
public:
|
|
int m_nnumber;
|
|
int m_bright;
|
|
|
|
CBufferT <CHART> m_szNamed;
|
|
};
|
|
|
|
template <class CHART> CBracketElxT <CHART> :: CBracketElxT(int nnumber, int bright)
|
|
{
|
|
m_nnumber = nnumber;
|
|
m_bright = bright;
|
|
}
|
|
|
|
template <class CHART> inline int CBracketElxT <CHART> :: CheckCaptureIndex(int & index, CContext * pContext) const
|
|
{
|
|
if( index >= pContext->m_capturestack.GetSize() )
|
|
index = pContext->m_capturestack.GetSize() - 4;
|
|
|
|
while(index >= 0)
|
|
{
|
|
if(pContext->m_capturestack[index] == m_nnumber)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
index -= 4;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// capturestack[index+0] => Group number
|
|
// capturestack[index+1] => Capture start pos
|
|
// capturestack[index+2] => Capture end pos
|
|
// capturestack[index+3] => Capture enclose z-index, zindex<0 means inner group with same name
|
|
//
|
|
template <class CHART> int CBracketElxT <CHART> :: 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(CheckCaptureIndex(index, pContext) && 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(CheckCaptureIndex(index, pContext))
|
|
{
|
|
if(pContext->m_capturestack[index + 3] < 0) // check inner group with same name
|
|
{
|
|
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 <class CHART> int CBracketElxT <CHART> :: MatchNext(CContext * pContext) const
|
|
{
|
|
int index = pContext->m_captureindex[m_nnumber];
|
|
if( ! CheckCaptureIndex(index, pContext) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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
|
|
CheckCaptureIndex(index, pContext);
|
|
|
|
// new index
|
|
pContext->m_captureindex[m_nnumber] = index;
|
|
}
|
|
else
|
|
{
|
|
if( pContext->m_capturestack[index + 2] >= 0 )
|
|
{
|
|
pContext->m_capturestack[index + 2] = -1;
|
|
pContext->m_capturestack[index + 3] = 0;
|
|
}
|
|
else
|
|
{
|
|
pContext->m_capturestack[index + 3] --;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Deletage
|
|
//
|
|
template <class CHART> 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 <CHART> m_szNamed;
|
|
};
|
|
|
|
template <class CHART> CDelegateElxT <CHART> :: CDelegateElxT(int ndata)
|
|
{
|
|
m_pelx = 0;
|
|
m_ndata = ndata;
|
|
}
|
|
|
|
template <class CHART> int CDelegateElxT <CHART> :: Match(CContext * pContext) const
|
|
{
|
|
if(m_pelx != 0)
|
|
return m_pelx->Match(pContext);
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
template <class CHART> int CDelegateElxT <CHART> :: MatchNext(CContext * pContext) const
|
|
{
|
|
if(m_pelx != 0)
|
|
return m_pelx->MatchNext(pContext);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Empty
|
|
//
|
|
template <int x> class CEmptyElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CEmptyElxT();
|
|
};
|
|
|
|
typedef CEmptyElxT <0> CEmptyElx;
|
|
|
|
//
|
|
// Global
|
|
//
|
|
template <int x> class CGlobalElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CGlobalElxT();
|
|
};
|
|
|
|
typedef CGlobalElxT <0> CGlobalElx;
|
|
|
|
//
|
|
// Repeat
|
|
//
|
|
template <int x> 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 <int x> class CGreedyElxT : public CRepeatElxT <x>
|
|
{
|
|
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 <int x> 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 <int x> class CListElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CListElxT(int brightleft);
|
|
|
|
public:
|
|
CBufferT <ElxInterface *> m_elxlist;
|
|
int m_brightleft;
|
|
};
|
|
|
|
typedef CListElxT <0> CListElx;
|
|
|
|
//
|
|
// Posix Elx
|
|
//
|
|
template <class CHART> 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 m_isblank(int c);
|
|
|
|
public:
|
|
int (*m_posixfun)(int);
|
|
int m_brightleft;
|
|
int m_byes;
|
|
};
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
template <class CHART> CPosixElxT <CHART> :: 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 = m_isblank ;
|
|
else m_posixfun = 0 ;
|
|
}
|
|
|
|
template <class CHART> int CPosixElxT <CHART> :: m_isblank(int c)
|
|
{
|
|
return c == 0x20 || c == '\t';
|
|
}
|
|
|
|
template <class CHART> int CPosixElxT <CHART> :: 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 <class CHART> int CPosixElxT <CHART> :: MatchNext(CContext * pContext) const
|
|
{
|
|
pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Possessive
|
|
//
|
|
template <int x> class CPossessiveElxT : public CGreedyElxT <x>
|
|
{
|
|
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 CHART> class CRangeElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CRangeElxT(int brightleft, int byes);
|
|
|
|
public:
|
|
int IsContainChar(CHART ch) const;
|
|
|
|
public:
|
|
CBufferT <CHART> m_ranges;
|
|
CBufferT <CHART> m_chars;
|
|
CBufferT <ElxInterface *> m_embeds;
|
|
|
|
public:
|
|
int m_brightleft;
|
|
int m_byes;
|
|
};
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
template <class CHART> CRangeElxT <CHART> :: CRangeElxT(int brightleft, int byes)
|
|
{
|
|
m_brightleft = brightleft;
|
|
m_byes = byes;
|
|
}
|
|
|
|
template <class CHART> int CRangeElxT <CHART> :: 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 && i<m_ranges.GetSize(); i+=2)
|
|
{
|
|
if(m_ranges[i] <= ch && ch <= m_ranges[i+1]) bsucc = 1;
|
|
}
|
|
|
|
for(i=0; !bsucc && i<m_chars.GetSize(); i++)
|
|
{
|
|
if(m_chars[i] == ch) bsucc = 1;
|
|
}
|
|
|
|
for(i=0; !bsucc && i<m_embeds.GetSize(); i++)
|
|
{
|
|
if(m_embeds[i]->Match(pContext))
|
|
{
|
|
pContext->m_nCurrentPos = npos;
|
|
bsucc = 1;
|
|
}
|
|
}
|
|
|
|
if( ! m_byes )
|
|
bsucc = ! bsucc;
|
|
|
|
if( bsucc )
|
|
pContext->m_nCurrentPos += m_brightleft ? -1 : 1;
|
|
|
|
return bsucc;
|
|
}
|
|
|
|
template <class CHART> int CRangeElxT <CHART> :: IsContainChar(CHART ch) const
|
|
{
|
|
int bsucc = 0, i;
|
|
|
|
// compare
|
|
for(i=0; !bsucc && i<m_ranges.GetSize(); i+=2)
|
|
{
|
|
if(m_ranges[i] <= ch && ch <= m_ranges[i+1]) bsucc = 1;
|
|
}
|
|
|
|
for(i=0; !bsucc && i<m_chars.GetSize(); i++)
|
|
{
|
|
if(m_chars[i] == ch) bsucc = 1;
|
|
}
|
|
|
|
return bsucc;
|
|
}
|
|
|
|
template <class CHART> int CRangeElxT <CHART> :: MatchNext(CContext * pContext) const
|
|
{
|
|
pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Reluctant
|
|
//
|
|
template <int x> class CReluctantElxT : public CRepeatElxT <x>
|
|
{
|
|
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 CHART> 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 <CHART> m_szPattern;
|
|
int m_brightleft;
|
|
int m_bignorecase;
|
|
};
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
template <class CHART> CStringElxT <CHART> :: CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase) : m_szPattern(fixed, nlength)
|
|
{
|
|
m_brightleft = brightleft;
|
|
m_bignorecase = bignorecase;
|
|
}
|
|
|
|
template <class CHART> int CStringElxT <CHART> :: 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 <class CHART> int CStringElxT <CHART> :: 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 CHART> class CConditionElxT : public ElxInterface
|
|
{
|
|
public:
|
|
int Match (CContext * pContext) const;
|
|
int MatchNext(CContext * pContext) const;
|
|
|
|
public:
|
|
CConditionElxT();
|
|
|
|
public:
|
|
// backref condition
|
|
int m_nnumber;
|
|
CBufferT <CHART> m_szNamed;
|
|
|
|
// elx condition
|
|
ElxInterface * m_pelxask;
|
|
|
|
// selection
|
|
ElxInterface * m_pelxyes, * m_pelxno;
|
|
};
|
|
|
|
template <class CHART> CConditionElxT <CHART> :: CConditionElxT()
|
|
{
|
|
m_nnumber = -1;
|
|
}
|
|
|
|
template <class CHART> int CConditionElxT <CHART> :: 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 <class CHART> int CConditionElxT <CHART> :: MatchNext(CContext * pContext) const
|
|
{
|
|
// pop
|
|
int ncsize = 0, condition_yes = 0;
|
|
|
|
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 <int x> 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 = 0, int nMaxNumber = -1);
|
|
MatchResultT <x> & operator = (const MatchResultT <x> &);
|
|
inline operator int() const { return IsMatched(); }
|
|
|
|
public:
|
|
CBufferT <int> 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 CHART> class CBuilderT
|
|
{
|
|
public:
|
|
typedef CDelegateElxT <CHART> CDelegateElx;
|
|
typedef CBracketElxT <CHART> CBracketElx;
|
|
typedef CBackrefElxT <CHART> CBackrefElx;
|
|
typedef CConditionElxT <CHART> CConditionElx;
|
|
|
|
// Methods
|
|
public:
|
|
ElxInterface * Build(const CBufferRefT <CHART> & pattern, int flags);
|
|
int GetNamedNumber(const CBufferRefT <CHART> & 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 <ElxInterface *> m_objlist;
|
|
CBufferT <ElxInterface *> m_grouplist;
|
|
CBufferT <CDelegateElx *> m_recursivelist;
|
|
CBufferT <CListElx *> m_namedlist;
|
|
CBufferT <CBackrefElx *> m_namedbackreflist;
|
|
CBufferT <CConditionElx *> 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 <CHART> 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 <class CHART> CBuilderT <CHART> :: CBuilderT() : m_pattern(0, 0), prev(0, 0), curr(0, 0), next(0, 0), nex2(0, 0)
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
template <class CHART> CBuilderT <CHART> :: ~CBuilderT()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
template <class CHART> int CBuilderT <CHART> :: GetNamedNumber(const CBufferRefT <CHART> & named) const
|
|
{
|
|
for(int i=0; i<m_namedlist.GetSize(); i++)
|
|
{
|
|
if( ! ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_szNamed.CompareNoCase(named) )
|
|
return ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_nnumber;
|
|
}
|
|
|
|
return -3;
|
|
}
|
|
|
|
template <class CHART> ElxInterface * CBuilderT <CHART> :: Build(const CBufferRefT <CHART> & 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; i<m_namedlist.GetSize(); i++)
|
|
{
|
|
CBracketElx * pleft = (CBracketElx *)m_namedlist[i]->m_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; i<m_nGroupCount; i++)
|
|
{
|
|
CBracketElx * pleft = (CBracketElx *)((CListElx*)m_grouplist[i])->m_elxlist[0];
|
|
|
|
if( pleft->m_nnumber > m_nMaxNumber )
|
|
m_nMaxNumber = pleft->m_nnumber;
|
|
}
|
|
|
|
// connect recursive
|
|
for(i=0; i<m_recursivelist.GetSize(); i++)
|
|
{
|
|
if( m_recursivelist[i]->m_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_nMaxNumber )
|
|
{
|
|
if( m_recursivelist[i]->m_ndata == 0 )
|
|
m_recursivelist[i]->m_pelx = m_pTopElx;
|
|
else for(int j=1; j<m_grouplist.GetSize(); j++)
|
|
{
|
|
if(m_recursivelist[i]->m_ndata == ((CBracketElx *)((CListElx*)m_grouplist[j])->m_elxlist[0])->m_nnumber)
|
|
{
|
|
m_recursivelist[i]->m_pelx = m_grouplist[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// named backref
|
|
for(i=0; i<m_namedbackreflist.GetSize(); i++)
|
|
{
|
|
m_namedbackreflist[i]->m_nnumber = GetNamedNumber(m_namedbackreflist[i]->m_szNamed);
|
|
}
|
|
|
|
// named condition
|
|
for(i=0; i<m_namedconditionlist.GetSize(); i++)
|
|
{
|
|
int nn = GetNamedNumber(m_namedconditionlist[i]->m_szNamed);
|
|
if( nn >= 0 )
|
|
{
|
|
m_namedconditionlist[i]->m_nnumber = nn;
|
|
m_namedconditionlist[i]->m_pelxask = 0;
|
|
}
|
|
}
|
|
|
|
return m_pTopElx;
|
|
}
|
|
|
|
template <class CHART> void CBuilderT <CHART> :: Clear()
|
|
{
|
|
for(int i=0; i<m_objlist.GetSize(); i++)
|
|
{
|
|
delete m_objlist[i];
|
|
}
|
|
|
|
m_objlist.Restore(0);
|
|
m_pTopElx = 0;
|
|
m_nMaxNumber = 0;
|
|
|
|
memset(m_pStockElxs, 0, sizeof(m_pStockElxs));
|
|
}
|
|
|
|
//
|
|
// hex to int
|
|
//
|
|
template <class CHART> unsigned int CBuilderT <CHART> :: Hex2Int(const CHART * pcsz, int length, int & used)
|
|
{
|
|
unsigned int result = 0;
|
|
int & i = used;
|
|
|
|
for(i=0; i<length; i++)
|
|
{
|
|
if(pcsz[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 <class CHART> inline ElxInterface * CBuilderT <CHART> :: Keep(ElxInterface * pelx)
|
|
{
|
|
m_objlist.Push(pelx);
|
|
return pelx;
|
|
}
|
|
|
|
template <class CHART> void CBuilderT <CHART> :: MoveNext()
|
|
{
|
|
// forwards
|
|
prev = curr;
|
|
curr = next;
|
|
next = nex2;
|
|
|
|
// get nex2
|
|
while( ! GetNext2() ) {};
|
|
}
|
|
|
|
template <class CHART> int CBuilderT <CHART> :: 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('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('['):
|
|
if( m_nCharsetDepth == 0 || m_pattern.At(m_nNextPos + 1, 0) == RCHART(':') )
|
|
{
|
|
m_nCharsetDepth ++;
|
|
nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
|
|
}
|
|
else
|
|
{
|
|
nex2 = CHART_INFO(ch, 0, 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 <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> (0, 0));
|
|
break;
|
|
|
|
case STOCKELX_DOT_NOT_ALL:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));
|
|
|
|
pRange->m_chars .Push(RCHART('\n'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
|
|
case STOCKELX_SPACE:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 1));
|
|
|
|
pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
|
|
case STOCKELX_DIGITAL_NOT:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));
|
|
|
|
pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
|
|
case STOCKELX_WORD_RIGHTLEFT:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> (1, 0));
|
|
break;
|
|
|
|
case STOCKELX_DOT_NOT_ALL_RIGHTLEFT:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));
|
|
|
|
pRange->m_chars .Push(RCHART('\n'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
|
|
case STOCKELX_SPACE_RIGHTLEFT:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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 <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 1));
|
|
|
|
pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
|
|
case STOCKELX_DIGITAL_RIGHTLEFT_NOT:
|
|
{
|
|
CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));
|
|
|
|
pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
|
|
|
|
pStockElxs[nStockId] = pRange;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// return
|
|
return pStockElxs[nStockId];
|
|
}
|
|
|
|
template <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <char> 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 <class CHART> ElxInterface * CBuilderT <CHART> :: BuildSimple(int & flags)
|
|
{
|
|
CBufferT <CHART> 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('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 <CHART> (fixed.GetBuffer(), fixed.GetSize(), flags & RIGHTTOLEFT, flags & IGNORECASE));
|
|
else
|
|
return GetStockElx(STOCKELX_EMPTY);
|
|
}
|
|
|
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
template <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <CHART> * pRange;
|
|
|
|
// create
|
|
if(curr == CHART_INFO(RCHART(':'), 1))
|
|
{
|
|
CBufferT <char> 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 <CHART> (posix.GetBuffer(), flags & RIGHTTOLEFT));
|
|
}
|
|
else if(curr == CHART_INFO(RCHART('^'), 1))
|
|
{
|
|
MoveNext(); // skip '^'
|
|
pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (flags & RIGHTTOLEFT, 0));
|
|
}
|
|
else
|
|
{
|
|
pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (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();
|
|
|
|
if( flags & IGNORECASE )
|
|
{
|
|
CBufferT <CHART> & ranges = pRange->m_ranges;
|
|
int i, oldcount = ranges.GetSize() / 2;
|
|
|
|
for(i=0; i<oldcount; i++)
|
|
{
|
|
CHART newmin, newmax;
|
|
|
|
if( ranges[i*2] <= RCHART('Z') && ranges[i*2+1] >= RCHART('A') )
|
|
{
|
|
newmin = tolower( max(RCHART('A'), ranges[i*2 ]) );
|
|
newmax = tolower( min(RCHART('Z'), ranges[i*2+1]) );
|
|
|
|
if( newmin < ranges[i*2] || newmax > ranges[i*2+1] )
|
|
{
|
|
ranges.Push(newmin);
|
|
ranges.Push(newmax);
|
|
}
|
|
}
|
|
|
|
if( ranges[i*2] <= RCHART('z') && ranges[i*2+1] >= RCHART('a') )
|
|
{
|
|
newmin = toupper( max(RCHART('a'), ranges[i*2 ]) );
|
|
newmax = toupper( min(RCHART('z'), ranges[i*2+1]) );
|
|
|
|
if( newmin < ranges[i*2] || newmax > ranges[i*2+1] )
|
|
{
|
|
ranges.Push(newmin);
|
|
ranges.Push(newmax);
|
|
}
|
|
}
|
|
}
|
|
|
|
CBufferT <CHART> & chars = pRange->m_chars;
|
|
oldcount = chars.GetSize();
|
|
for(i=0; i<oldcount; i++)
|
|
{
|
|
if( isupper(chars[i]) && ! pRange->IsContainChar(tolower(chars[i])) )
|
|
chars.Push(tolower(chars[i]));
|
|
|
|
if( islower(chars[i]) && ! pRange->IsContainChar(toupper(chars[i])) )
|
|
chars.Push(toupper(chars[i]));
|
|
}
|
|
}
|
|
|
|
return pRange;
|
|
}
|
|
}
|
|
|
|
return GetStockElx(STOCKELX_EMPTY);
|
|
}
|
|
|
|
template <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <CHART> & name = pleft->m_szNamed;
|
|
CBufferT <char> 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 <num>
|
|
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 <CHART> & name = pDelegate->m_szNamed;
|
|
CBufferT <char> 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 <num>
|
|
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 <char> 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 <char> 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 <char> 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 <class CHART> ElxInterface * CBuilderT <CHART> :: BuildBoundary(int & flags)
|
|
{
|
|
// char
|
|
CHART ch = curr.ch;
|
|
|
|
// skip
|
|
MoveNext();
|
|
|
|
switch(ch)
|
|
{
|
|
case RCHART('^'):
|
|
return Keep(new CBoundaryElxT <CHART> ((flags & MULTILINE) ? BOUNDARY_LINE_BEGIN : BOUNDARY_FILE_BEGIN));
|
|
|
|
case RCHART('$'):
|
|
return Keep(new CBoundaryElxT <CHART> ((flags & MULTILINE) ? BOUNDARY_LINE_END : BOUNDARY_FILE_END));
|
|
|
|
case RCHART('b'):
|
|
return Keep(new CBoundaryElxT <CHART> (BOUNDARY_WORD_EDGE));
|
|
|
|
case RCHART('B'):
|
|
return Keep(new CBoundaryElxT <CHART> (BOUNDARY_WORD_EDGE, 0));
|
|
|
|
case RCHART('A'):
|
|
return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_BEGIN));
|
|
|
|
case RCHART('Z'):
|
|
return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_END_N));
|
|
|
|
case RCHART('z'):
|
|
return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_END));
|
|
|
|
case RCHART('G'):
|
|
if(flags & GLOBAL)
|
|
return Keep(new CGlobalElx());
|
|
else
|
|
return GetStockElx(STOCKELX_EMPTY);
|
|
|
|
default:
|
|
return GetStockElx(STOCKELX_EMPTY);
|
|
}
|
|
}
|
|
|
|
template <class CHART> ElxInterface * CBuilderT <CHART> :: 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 <CHART> * pbackref = (CBackrefElxT <CHART> *)Keep(new CBackrefElxT <CHART> (-1, flags & RIGHTTOLEFT, flags & IGNORECASE));
|
|
|
|
MoveNext(); // skip '<' or '\''
|
|
|
|
// save name
|
|
CBufferT <CHART> & name = pbackref->m_szNamed;
|
|
CBufferT <char> 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 <num>
|
|
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 <CHART> (nbackref, flags & RIGHTTOLEFT, flags & IGNORECASE));
|
|
}
|
|
}
|
|
|
|
template <class CHART> int CBuilderT <CHART> :: 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<sizeof(CHART)*3 + s; i++)
|
|
{
|
|
if(str[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 CHART> 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 <CHART> m_builder;
|
|
};
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
template <class CHART> CRegexpT <CHART> :: CRegexpT(const CHART * pattern, int flags)
|
|
{
|
|
Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
|
|
}
|
|
|
|
template <class CHART> CRegexpT <CHART> :: CRegexpT(const CHART * pattern, int length, int flags)
|
|
{
|
|
Compile(pattern, length, flags);
|
|
}
|
|
|
|
template <class CHART> inline void CRegexpT <CHART> :: Compile(const CHART * pattern, int flags)
|
|
{
|
|
Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
|
|
}
|
|
|
|
template <class CHART> void CRegexpT <CHART> :: Compile(const CHART * pattern, int length, int flags)
|
|
{
|
|
m_builder.Clear();
|
|
if(pattern != 0) m_builder.Build(CBufferRefT<CHART>(pattern, length), flags);
|
|
}
|
|
|
|
template <class CHART> inline MatchResult CRegexpT <CHART> :: MatchExact(const CHART * tstring, CContext * pContext) const
|
|
{
|
|
return MatchExact(tstring, CBufferRefT<CHART>(tstring).GetSize(), pContext);
|
|
}
|
|
|
|
template <class CHART> MatchResult CRegexpT <CHART> :: 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 <class CHART> MatchResult CRegexpT <CHART> :: Match(const CHART * tstring, int start, CContext * pContext) const
|
|
{
|
|
return Match(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
|
|
}
|
|
|
|
template <class CHART> MatchResult CRegexpT <CHART> :: 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 <class CHART> MatchResult CRegexpT <CHART> :: 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 <class CHART> inline CContext * CRegexpT <CHART> :: PrepareMatch(const CHART * tstring, int start, CContext * pContext) const
|
|
{
|
|
return PrepareMatch(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
|
|
}
|
|
|
|
template <class CHART> CContext * CRegexpT <CHART> :: 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 <class CHART> inline int CRegexpT <CHART> :: GetNamedGroupNumber(const CHART * group_name) const
|
|
{
|
|
return m_builder.GetNamedNumber(group_name);
|
|
}
|
|
|
|
template <class CHART> CHART * CRegexpT <CHART> :: Replace(const CHART * tstring, const CHART * replaceto, int start, int ntimes, MatchResult * result, CContext * pContext) const
|
|
{
|
|
int result_length = 0;
|
|
return Replace(tstring, CBufferRefT<CHART>(tstring).GetSize(), replaceto, CBufferRefT<CHART>(replaceto).GetSize(), result_length, start, ntimes, result, pContext);
|
|
}
|
|
|
|
template <class CHART> CHART * CRegexpT <CHART> :: 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
|
|
{
|
|
if(m_builder.m_pTopElx == 0) return 0;
|
|
|
|
// --- compile replace to ---
|
|
|
|
CBufferT <int> compiledto;
|
|
|
|
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 CRegexpT <CHART> rtoreg(rtoptn);
|
|
|
|
MatchResult local_result(0), * result = remote_result ? remote_result : & local_result;
|
|
|
|
// prepare
|
|
CContext * pContext = PrepareMatch(replaceto, to_length, -1, oContext);
|
|
int lastIndex = 0, nmatch = 0;
|
|
|
|
while( ((*result) = rtoreg.Match(pContext)).IsMatched() )
|
|
{
|
|
int delta = result->GetStart() - lastIndex;
|
|
if( delta > 0 )
|
|
{
|
|
compiledto.Push(lastIndex);
|
|
compiledto.Push(delta);
|
|
}
|
|
|
|
lastIndex = result->GetStart();
|
|
delta = 2;
|
|
|
|
switch(replaceto[lastIndex + 1])
|
|
{
|
|
case RCHART('$'):
|
|
compiledto.Push(lastIndex);
|
|
compiledto.Push(1);
|
|
break;
|
|
|
|
case RCHART('&'):
|
|
case RCHART('`'):
|
|
case RCHART('\''):
|
|
case RCHART('+'):
|
|
case RCHART('_'):
|
|
compiledto.Push(-1);
|
|
compiledto.Push((int)replaceto[lastIndex + 1]);
|
|
|
|
case RCHART('{'):
|
|
delta = result->GetEnd() - result->GetStart();
|
|
nmatch = m_builder.GetNamedNumber(CBufferRefT <CHART> (replaceto + (lastIndex + 2), delta - 3));
|
|
|
|
if(nmatch > 0 && nmatch <= m_builder.m_nMaxNumber)
|
|
{
|
|
compiledto.Push(-2);
|
|
compiledto.Push(nmatch);
|
|
}
|
|
else
|
|
{
|
|
compiledto.Push(lastIndex);
|
|
compiledto.Push(delta);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
nmatch = 0;
|
|
for(delta=1; delta<=3; delta++)
|
|
{
|
|
CHART ch = replaceto[lastIndex + 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)
|
|
{
|
|
compiledto.Push(lastIndex);
|
|
compiledto.Push(1);
|
|
}
|
|
else
|
|
{
|
|
compiledto.Push(-2);
|
|
compiledto.Push(nmatch);
|
|
}
|
|
break;
|
|
}
|
|
|
|
lastIndex += delta;
|
|
}
|
|
|
|
if(lastIndex < to_length)
|
|
{
|
|
compiledto.Push(lastIndex);
|
|
compiledto.Push(to_length - lastIndex);
|
|
}
|
|
|
|
int rightleft = m_builder.m_nFlags & RIGHTTOLEFT;
|
|
|
|
int tb = rightleft ? compiledto.GetSize() - 2 : 0;
|
|
int te = rightleft ? -2 : compiledto.GetSize();
|
|
int ts = rightleft ? -2 : 2;
|
|
|
|
// --- compile complete ---
|
|
|
|
int beginpos = rightleft ? string_length : 0;
|
|
int endpos = rightleft ? 0 : string_length;
|
|
|
|
int toIndex0 = 0;
|
|
int toIndex1 = 0;
|
|
int i, ntime;
|
|
|
|
CBufferT <const CHART *> buffer;
|
|
|
|
// prepare
|
|
pContext = PrepareMatch(tstring, string_length, start, pContext);
|
|
lastIndex = beginpos;
|
|
|
|
// Match
|
|
for(ntime = 0; ntimes < 0 || ntime < ntimes; ntime ++)
|
|
{
|
|
(*result) = Match(pContext);
|
|
|
|
if( ! result->IsMatched() )
|
|
break;
|
|
|
|
// before
|
|
if( rightleft )
|
|
{
|
|
int distance = lastIndex - result->GetEnd();
|
|
if( distance )
|
|
{
|
|
buffer.Push(tstring + result->GetEnd());
|
|
buffer.Push((const CHART *)distance);
|
|
|
|
toIndex1 -= distance;
|
|
}
|
|
lastIndex = result->GetStart();
|
|
}
|
|
else
|
|
{
|
|
int distance = result->GetStart() - lastIndex;
|
|
if( distance )
|
|
{
|
|
buffer.Push(tstring + lastIndex);
|
|
buffer.Push((const CHART *)distance);
|
|
|
|
toIndex1 += distance;
|
|
}
|
|
lastIndex = result->GetEnd();
|
|
}
|
|
|
|
toIndex0 = toIndex1;
|
|
|
|
// middle
|
|
for(i=tb; i!=te; i+=ts)
|
|
{
|
|
int off = compiledto[i];
|
|
int len = compiledto[i + 1];
|
|
|
|
const CHART * sub = replaceto + off;
|
|
|
|
if( off == -1 )
|
|
{
|
|
switch(RCHART(len))
|
|
{
|
|
case RCHART('&'):
|
|
sub = tstring + result->GetStart();
|
|
len = result->GetEnd() - result->GetStart();
|
|
break;
|
|
|
|
case RCHART('`'):
|
|
sub = tstring;
|
|
len = result->GetStart();
|
|
break;
|
|
|
|
case RCHART('\''):
|
|
sub = tstring + result->GetEnd();
|
|
len = string_length - result->GetEnd();
|
|
break;
|
|
|
|
case RCHART('+'):
|
|
for(nmatch = result->MaxGroupNumber(); nmatch >= 0; nmatch --)
|
|
{
|
|
if(result->GetGroupStart(nmatch) >= 0) break;
|
|
}
|
|
sub = tstring + result->GetGroupStart(nmatch);
|
|
len = result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch);
|
|
break;
|
|
|
|
case RCHART('_'):
|
|
sub = tstring;
|
|
len = string_length;
|
|
break;
|
|
}
|
|
}
|
|
else if( off == -2 )
|
|
{
|
|
sub = tstring + result->GetGroupStart(len);
|
|
len = result->GetGroupEnd(len) - result->GetGroupStart(len);
|
|
}
|
|
|
|
buffer.Push(sub);
|
|
buffer.Push((const CHART *)len);
|
|
|
|
toIndex1 += rightleft ? (-len) : len;
|
|
}
|
|
}
|
|
|
|
// after
|
|
if(rightleft)
|
|
{
|
|
if(endpos < lastIndex)
|
|
{
|
|
buffer.Push(tstring + endpos);
|
|
buffer.Push((const CHART *)(lastIndex - endpos));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(lastIndex < endpos)
|
|
{
|
|
buffer.Push(tstring + lastIndex);
|
|
buffer.Push((const CHART *)(endpos - lastIndex));
|
|
}
|
|
}
|
|
|
|
if(oContext == 0) ReleaseContext(pContext);
|
|
|
|
// join string
|
|
result_length = 0;
|
|
for(i=0; i<buffer.GetSize(); i+=2)
|
|
{
|
|
result_length += (int)buffer[i+1];
|
|
}
|
|
|
|
CBufferT <CHART> result_string;
|
|
result_string.Prepare(result_length);
|
|
result_string.Restore(0);
|
|
|
|
if(rightleft)
|
|
{
|
|
for(i=buffer.GetSize()-2; i>=0; i-=2)
|
|
{
|
|
result_string.Append(buffer[i], (int)buffer[i+1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(i=0; i<buffer.GetSize(); i+=2)
|
|
{
|
|
result_string.Append(buffer[i], (int)buffer[i+1]);
|
|
}
|
|
}
|
|
|
|
result_string.Append(0);
|
|
|
|
result->m_result.Append(result_length, 3);
|
|
result->m_result.Append(ntime);
|
|
|
|
if(rightleft)
|
|
{
|
|
result->m_result.Append(result_length - toIndex1);
|
|
result->m_result.Append(result_length - toIndex0);
|
|
}
|
|
else
|
|
{
|
|
result->m_result.Append(toIndex0);
|
|
result->m_result.Append(toIndex1);
|
|
}
|
|
|
|
return result_string.Detach();
|
|
}
|
|
|
|
template <class CHART> inline void CRegexpT <CHART> :: ReleaseString(CHART * tstring)
|
|
{
|
|
if(tstring != 0) free(tstring);
|
|
}
|
|
|
|
template <class CHART> inline void CRegexpT <CHART> :: ReleaseContext(CContext * pContext)
|
|
{
|
|
if(pContext != 0) delete pContext;
|
|
}
|
|
|
|
//
|
|
// All implementations
|
|
//
|
|
template <int x> CAlternativeElxT <x> :: CAlternativeElxT()
|
|
{
|
|
}
|
|
|
|
template <int x> int CAlternativeElxT <x> :: 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 x> int CAlternativeElxT <x> :: 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 <int x> CAssertElxT <x> :: CAssertElxT(ElxInterface * pelx, int byes)
|
|
{
|
|
m_pelx = pelx;
|
|
m_byes = byes;
|
|
}
|
|
|
|
template <int x> int CAssertElxT <x> :: 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 x> int CAssertElxT <x> :: 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 <int x> CEmptyElxT <x> :: CEmptyElxT()
|
|
{
|
|
}
|
|
|
|
template <int x> int CEmptyElxT <x> :: Match(CContext *) const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CEmptyElxT <x> :: MatchNext(CContext *) const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// globalx.cpp: implementation of the CGlobalElx class.
|
|
//
|
|
template <int x> CGlobalElxT <x> ::CGlobalElxT()
|
|
{
|
|
}
|
|
|
|
template <int x> int CGlobalElxT <x> :: Match(CContext * pContext) const
|
|
{
|
|
return pContext->m_nCurrentPos == pContext->m_nBeginPos;
|
|
}
|
|
|
|
template <int x> int CGlobalElxT <x> :: MatchNext(CContext *) const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// greedelx.cpp: implementation of the CGreedyElx class.
|
|
//
|
|
template <int x> CGreedyElxT <x> :: CGreedyElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x> (pelx, nmin)
|
|
{
|
|
m_nvart = nmax - nmin;
|
|
}
|
|
|
|
template <int x> int CGreedyElxT <x> :: Match(CContext * pContext) const
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchFixed(pContext) )
|
|
return 0;
|
|
|
|
while( ! MatchVart(pContext) )
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CGreedyElxT <x> :: MatchNext(CContext * pContext) const
|
|
{
|
|
if( MatchNextVart(pContext) )
|
|
return 1;
|
|
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
|
|
while( ! MatchVart(pContext) )
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CGreedyElxT <x> :: MatchVart(CContext * pContext) const
|
|
{
|
|
int n = 0;
|
|
int nbegin = pContext->m_nCurrentPos;
|
|
|
|
while(n < m_nvart && CRepeatElxT <x> :: m_pelx->Match(pContext))
|
|
{
|
|
while(pContext->m_nCurrentPos == nbegin)
|
|
{
|
|
if( ! CRepeatElxT <x> :: 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 x> int CGreedyElxT <x> :: MatchNextVart(CContext * pContext) const
|
|
{
|
|
int n = 0;
|
|
pContext->m_stack.Pop(n);
|
|
|
|
if(n == 0) return 0;
|
|
|
|
if( ! CRepeatElxT <x> :: m_pelx->MatchNext(pContext) )
|
|
{
|
|
n --;
|
|
}
|
|
|
|
pContext->m_stack.Push(n);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// indepelx.cpp: implementation of the CIndependentElx class.
|
|
//
|
|
template <int x> CIndependentElxT <x> :: CIndependentElxT(ElxInterface * pelx)
|
|
{
|
|
m_pelx = pelx;
|
|
}
|
|
|
|
template <int x> int CIndependentElxT <x> :: 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 x> int CIndependentElxT <x> :: 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 <int x> CListElxT <x> :: CListElxT(int brightleft)
|
|
{
|
|
m_brightleft = brightleft;
|
|
}
|
|
|
|
template <int x> int CListElxT <x> :: 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 x> int CListElxT <x> :: 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 <int x> MatchResultT <x> :: 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 <int x> inline int MatchResultT <x> :: IsMatched() const
|
|
{
|
|
return m_result.At(0, 0);
|
|
}
|
|
|
|
template <int x> inline int MatchResultT <x> :: MaxGroupNumber() const
|
|
{
|
|
return m_result.At(1, 0);
|
|
}
|
|
|
|
template <int x> inline int MatchResultT <x> :: GetStart() const
|
|
{
|
|
return m_result.At(2, -1);
|
|
}
|
|
|
|
template <int x> inline int MatchResultT <x> :: GetEnd() const
|
|
{
|
|
return m_result.At(3, -1);
|
|
}
|
|
|
|
template <int x> inline int MatchResultT <x> :: GetGroupStart(int nGroupNumber) const
|
|
{
|
|
return m_result.At(2 + nGroupNumber * 2, -1);
|
|
}
|
|
|
|
template <int x> inline int MatchResultT <x> :: GetGroupEnd(int nGroupNumber) const
|
|
{
|
|
return m_result.At(2 + nGroupNumber * 2 + 1, -1);
|
|
}
|
|
|
|
template <int x> MatchResultT <x> & MatchResultT <x> :: operator = (const MatchResultT <x> & 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 <int x> CPossessiveElxT <x> :: CPossessiveElxT(ElxInterface * pelx, int nmin, int nmax) : CGreedyElxT <x> (pelx, nmin, nmax)
|
|
{
|
|
}
|
|
|
|
template <int x> int CPossessiveElxT <x> :: 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 <x> :: MatchFixed(pContext) )
|
|
{
|
|
bsucc = 0;
|
|
}
|
|
else
|
|
{
|
|
while( ! CGreedyElxT <x> :: MatchVart(pContext) )
|
|
{
|
|
if( ! CRepeatElxT <x> :: 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 x> int CPossessiveElxT <x> :: 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 <int x> CReluctantElxT <x> :: CReluctantElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x> (pelx, nmin)
|
|
{
|
|
m_nvart = nmax - nmin;
|
|
}
|
|
|
|
template <int x> int CReluctantElxT <x> :: Match(CContext * pContext) const
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchFixed(pContext) )
|
|
return 0;
|
|
|
|
while( ! MatchVart(pContext) )
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CReluctantElxT <x> :: MatchNext(CContext * pContext) const
|
|
{
|
|
if( MatchNextVart(pContext) )
|
|
return 1;
|
|
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
|
|
while( ! MatchVart(pContext) )
|
|
{
|
|
if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CReluctantElxT <x> :: MatchVart(CContext * pContext) const
|
|
{
|
|
pContext->m_stack.Push(0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <int x> int CReluctantElxT <x> :: MatchNextVart(CContext * pContext) const
|
|
{
|
|
int n = 0, nbegin = pContext->m_nCurrentPos;
|
|
|
|
pContext->m_stack.Pop(n);
|
|
|
|
if(n < m_nvart && CRepeatElxT <x> :: m_pelx->Match(pContext))
|
|
{
|
|
while(pContext->m_nCurrentPos == nbegin)
|
|
{
|
|
if( ! CRepeatElxT <x> :: 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 <x> :: 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 <int x> CRepeatElxT <x> :: CRepeatElxT(ElxInterface * pelx, int ntimes)
|
|
{
|
|
m_pelx = pelx;
|
|
m_nfixed = ntimes;
|
|
}
|
|
|
|
template <int x> int CRepeatElxT <x> :: Match(CContext * pContext) const
|
|
{
|
|
return MatchFixed(pContext);
|
|
}
|
|
|
|
template <int x> int CRepeatElxT <x> :: MatchNext(CContext * pContext) const
|
|
{
|
|
return MatchNextFixed(pContext);
|
|
}
|
|
|
|
template <int x> int CRepeatElxT <x> :: 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 x> int CRepeatElxT <x> :: 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 <char> CRegexpA;
|
|
typedef CRegexpT <unsigned short> CRegexpW;
|
|
|
|
#if defined(_UNICODE) || defined(UNICODE)
|
|
typedef CRegexpW CRegexp;
|
|
#else
|
|
typedef CRegexpA CRegexp;
|
|
#endif
|
|
|
|
#endif//__DEELX_REGEXP__H__
|