regex

   1 /*
   2 * Copyright 2016 E-Tool, Inc.
   3 */
   4 
   5 #ifndef regex_h
   6 #define regex_h
   7 
   8 #include <memory.h>
   9 #include <ctype.h>
  10 #include <limits.h>
  11 #include <string.h>
  12 #include <stdlib.h>
  13 
  14 extern "C" {
  15     typedef int(*POSIX_FUNC)(int);
  16     int isblank(int c);
  17 }
  18 
  19 //
  20 // Data Reference
  21 //
  22 template <class ELT> class CBufferRefT
  23 {
  24 public:
  25     CBufferRefT(const ELT * pcsz, int length);
  26     CBufferRefT(const ELT * pcsz);
  27 
  28 public:
  29     int nCompare(const ELT * pcsz) const;
  30     int nCompareNoCase(const ELT * pcsz) const;
  31     int  Compare(const ELT * pcsz) const;
  32     int  CompareNoCase(const ELT * pcsz) const;
  33     int  Compare(const CBufferRefT <ELT> &) const;
  34     int  CompareNoCase(const CBufferRefT <ELT> &) const;
  35 
  36     ELT At(int nIndex, ELT def = 0) const;
  37     ELT operator [] (int nIndex) const;
  38 
  39     const ELT * GetBuffer() const;
  40     int GetSize() const;
  41 
  42 public:
  43     virtual ~CBufferRefT();
  44 
  45     // Content
  46 protected:
  47     ELT * m_pBuffer;
  48     int         m_nSize;
  49 };
  50 
  51 //
  52 // Implemenation
  53 //
  54 template <class ELT> CBufferRefT <ELT> ::CBufferRefT(const ELT * pcsz, int length)
  55 {
  56     m_pBuffer = (ELT *)pcsz;
  57     m_nSize = length;
  58 }
  59 
  60 template <class ELT> CBufferRefT <ELT> ::CBufferRefT(const ELT * pcsz)
  61 {
  62     m_pBuffer = (ELT *)pcsz;
  63     m_nSize = 0;
  64 
  65     if (pcsz != 0) while (m_pBuffer[m_nSize] != 0) m_nSize++;
  66 }
  67 
  68 template <class ELT> int CBufferRefT <ELT> ::nCompare(const ELT * pcsz) const
  69 {
  70     for (int i = 0; i < m_nSize; i++)
  71     {
  72         if (m_pBuffer[i] != pcsz[i])
  73             return m_pBuffer[i] - pcsz[i];
  74     }
  75 
  76     return 0;
  77 }
  78 
  79 template <class ELT> int CBufferRefT <ELT> ::nCompareNoCase(const ELT * pcsz) const
  80 {
  81     for (int i = 0; i < m_nSize; i++)
  82     {
  83         if (m_pBuffer[i] != pcsz[i])
  84         {
  85             if (toupper((int)m_pBuffer[i]) != toupper((int)pcsz[i]))
  86                 return m_pBuffer[i] - pcsz[i];
  87         }
  88     }
  89 
  90     return 0;
  91 }
  92 
  93 template <class ELT> inline int CBufferRefT <ELT> ::Compare(const ELT * pcsz) const
  94 {
  95     return nCompare(pcsz) ? 1 : (int)pcsz[m_nSize];
  96 }
  97 
  98 template <class ELT> inline int CBufferRefT <ELT> ::CompareNoCase(const ELT * pcsz) const
  99 {
 100     return nCompareNoCase(pcsz) ? 1 : (int)pcsz[m_nSize];
 101 }
 102 
 103 template <class ELT> inline int CBufferRefT <ELT> ::Compare(const CBufferRefT <ELT> & cref) const
 104 {
 105     return m_nSize == cref.m_nSize ? nCompare(cref.GetBuffer()) : 1;
 106 }
 107 
 108 template <class ELT> inline int CBufferRefT <ELT> ::CompareNoCase(const CBufferRefT <ELT> & cref) const
 109 {
 110     return m_nSize == cref.m_nSize ? nCompareNoCase(cref.GetBuffer()) : 1;
 111 }
 112 
 113 template <class ELT> inline ELT CBufferRefT <ELT> ::At(int nIndex, ELT def) const
 114 {
 115     return nIndex >= m_nSize ? def : m_pBuffer[nIndex];
 116 }
 117 
 118 template <class ELT> inline ELT CBufferRefT <ELT> :: operator [] (int nIndex) const
 119 {
 120     return nIndex >= m_nSize ? 0 : m_pBuffer[nIndex];
 121 }
 122 
 123 template <class ELT> const ELT * CBufferRefT <ELT> ::GetBuffer() const
 124 {
 125     static const ELT _def[] = { 0 }; return m_pBuffer ? m_pBuffer : _def;
 126 }
 127 
 128 template <class ELT> inline int CBufferRefT <ELT> ::GetSize() const
 129 {
 130     return m_nSize;
 131 }
 132 
 133 template <class ELT> CBufferRefT <ELT> :: ~CBufferRefT()
 134 {
 135 }
 136 
 137 //
 138 // Data Buffer
 139 //
 140 template <class ELT> class CBufferT : public CBufferRefT <ELT>
 141 {
 142 public:
 143     CBufferT(const ELT * pcsz, int length);
 144     CBufferT(const ELT * pcsz);
 145     CBufferT();
 146 
 147 public:
 148     ELT & operator [] (int nIndex);
 149     const ELT & operator [] (int nIndex) const;
 150     void  Append(const ELT * pcsz, int length, int eol = 0);
 151     void  Append(ELT el, int eol = 0);
 152 
 153 public:
 154     void  Push(ELT   el);
 155     void  Push(const CBufferRefT<ELT> & buf);
 156     int   Pop(ELT & el);
 157     int   Pop(CBufferT<ELT> & buf);
 158     int   Peek(ELT & el) const;
 159 
 160 public:
 161     const ELT * GetBuffer() const;
 162     ELT * GetBuffer();
 163     ELT * Detach();
 164     void  Release();
 165     void  Prepare(int index, int fill = 0);
 166     void  Restore(int size);
 167 
 168     ELT * PrepareInsert(int nPos, int nSize)
 169     {
 170         int nOldSize = CBufferRefT<ELT>::m_nSize;
 171         Restore(nPos > CBufferRefT<ELT>::m_nSize ? nPos : CBufferRefT<ELT>::m_nSize + nSize);
 172 
 173         if (nPos < nOldSize)
 174         {
 175             ELT * from = CBufferRefT<ELT>::m_pBuffer + nPos, *to = CBufferRefT<ELT>::m_pBuffer + nPos + nSize;
 176             memmove(to, from, sizeof(ELT) * (nOldSize - nPos));
 177         }
 178 
 179         return CBufferRefT<ELT>::m_pBuffer + nPos;
 180     }
 181 
 182     void Insert(int nIndex, const ELT & rT)
 183     {
 184         Insert(nIndex, &rT, 1);
 185     }
 186 
 187     void Insert(int nIndex, const ELT * pT, int nSize)
 188     {
 189         memcpy(PrepareInsert(nIndex, nSize), pT, sizeof(ELT) * nSize);
 190     }
 191 
 192     void Remove(int nIndex)
 193     {
 194         Remove(nIndex, 1);
 195     }
 196 
 197     void Remove(int nIndex, int nSize)
 198     {
 199         if (nIndex < CBufferRefT <ELT> ::m_nSize)
 200         {
 201             if (nIndex + nSize >= CBufferRefT <ELT> ::m_nSize)
 202             {
 203                 Restore(nIndex);
 204             }
 205             else
 206             {
 207                 memmove(CBufferRefT <ELT> ::m_pBuffer + nIndex, CBufferRefT <ELT> ::m_pBuffer + nIndex + nSize, sizeof(ELT) * (CBufferRefT <ELT> ::m_nSize - nIndex - nSize));
 208                 Restore(CBufferRefT <ELT> ::m_nSize - nSize);
 209             }
 210         }
 211     }
 212 
 213     void SetMaxLength(int nSize)
 214     {
 215         if (nSize > m_nMaxLength)
 216         {
 217             if (m_nMaxLength < 8)
 218                 m_nMaxLength = 8;
 219 
 220             if (nSize > m_nMaxLength)
 221                 m_nMaxLength *= 2;
 222 
 223             if (nSize > m_nMaxLength)
 224             {
 225                 m_nMaxLength = nSize + 11;
 226                 m_nMaxLength -= m_nMaxLength & 0x07;
 227             }
 228 
 229             CBufferRefT <ELT> ::m_pBuffer = (ELT *)realloc(CBufferRefT <ELT> ::m_pBuffer, sizeof(ELT) * m_nMaxLength);
 230         }
 231     }
 232 
 233 public:
 234     virtual ~CBufferT();
 235 
 236     // Content
 237 protected:
 238     int   m_nMaxLength;
 239 };
 240 
 241 //
 242 // Implemenation
 243 //
 244 template <class ELT> CBufferT <ELT> ::CBufferT(const ELT * pcsz, int length) : CBufferRefT <ELT>(0, length)
 245 {
 246     m_nMaxLength = CBufferRefT <ELT> ::m_nSize + 1;
 247 
 248     CBufferRefT <ELT> ::m_pBuffer = (ELT *)malloc(sizeof(ELT) * m_nMaxLength);
 249     memcpy(CBufferRefT<ELT>::m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> ::m_nSize);
 250     CBufferRefT<ELT>::m_pBuffer[CBufferRefT <ELT> ::m_nSize] = 0;
 251 }
 252 
 253 template <class ELT> CBufferT <ELT> ::CBufferT(const ELT * pcsz) : CBufferRefT <ELT>(pcsz)
 254 {
 255     m_nMaxLength = CBufferRefT <ELT> ::m_nSize + 1;
 256 
 257     CBufferRefT <ELT> ::m_pBuffer = (ELT *)malloc(sizeof(ELT) * m_nMaxLength);
 258     memcpy(CBufferRefT<ELT>::m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> ::m_nSize);
 259     CBufferRefT<ELT>::m_pBuffer[CBufferRefT <ELT> ::m_nSize] = 0;
 260 }
 261 
 262 template <class ELT> CBufferT <ELT> ::CBufferT() : CBufferRefT <ELT>(0, 0)
 263 {
 264     m_nMaxLength = 0;
 265     CBufferRefT<ELT>::m_pBuffer = 0;
 266 }
 267 
 268 template <class ELT> inline ELT & CBufferT <ELT> :: operator [] (int nIndex)
 269 {
 270     return CBufferRefT<ELT>::m_pBuffer[nIndex];
 271 }
 272 
 273 template <class ELT> inline const ELT & CBufferT <ELT> :: operator [] (int nIndex) const
 274 {
 275     return CBufferRefT<ELT>::m_pBuffer[nIndex];
 276 }
 277 
 278 template <class ELT> void CBufferT <ELT> ::Append(const ELT * pcsz, int length, int eol)
 279 {
 280     int nNewLength = m_nMaxLength;
 281 
 282     // Check length
 283     if (nNewLength < 8)
 284         nNewLength = 8;
 285 
 286     if (CBufferRefT <ELT> ::m_nSize + length + eol > nNewLength)
 287         nNewLength *= 2;
 288 
 289     if (CBufferRefT <ELT> ::m_nSize + length + eol > nNewLength)
 290     {
 291         nNewLength = CBufferRefT <ELT> ::m_nSize + length + eol + 11;
 292         nNewLength -= nNewLength % 8;
 293     }
 294 
 295     // Realloc
 296     if (nNewLength > m_nMaxLength)
 297     {
 298         CBufferRefT <ELT> ::m_pBuffer = (ELT *)realloc(CBufferRefT<ELT>::m_pBuffer, sizeof(ELT) * nNewLength);
 299         m_nMaxLength = nNewLength;
 300     }
 301 
 302     // Append
 303     memcpy(CBufferRefT<ELT>::m_pBuffer + CBufferRefT <ELT> ::m_nSize, pcsz, sizeof(ELT) * length);
 304     CBufferRefT <ELT> ::m_nSize += length;
 305 
 306     if (eol > 0) CBufferRefT<ELT>::m_pBuffer[CBufferRefT <ELT> ::m_nSize] = 0;
 307 }
 308 
 309 template <class ELT> inline void CBufferT <ELT> ::Append(ELT el, int eol)
 310 {
 311     Append(&el, 1, eol);
 312 }
 313 
 314 template <class ELT> void CBufferT <ELT> ::Push(ELT el)
 315 {
 316     // Realloc
 317     if (CBufferRefT <ELT> ::m_nSize >= m_nMaxLength)
 318     {
 319         int nNewLength = m_nMaxLength * 2;
 320         if (nNewLength < 8) nNewLength = 8;
 321 
 322         CBufferRefT <ELT> ::m_pBuffer = (ELT *)realloc(CBufferRefT<ELT>::m_pBuffer, sizeof(ELT) * nNewLength);
 323         m_nMaxLength = nNewLength;
 324     }
 325 
 326     // Append
 327     CBufferRefT<ELT>::m_pBuffer[CBufferRefT <ELT> ::m_nSize++] = el;
 328 }
 329 
 330 template <class ELT> void CBufferT <ELT> ::Push(const CBufferRefT<ELT> & buf)
 331 {
 332     for (int i = 0; i < buf.GetSize(); i++)
 333     {
 334         Push(buf[i]);
 335     }
 336 
 337     Push((ELT)buf.GetSize());
 338 }
 339 
 340 template <class ELT> inline int CBufferT <ELT> ::Pop(ELT & el)
 341 {
 342     if (CBufferRefT <ELT> ::m_nSize > 0)
 343     {
 344         el = CBufferRefT<ELT>::m_pBuffer[--CBufferRefT <ELT> ::m_nSize];
 345         return 1;
 346     }
 347     else
 348     {
 349         return 0;
 350     }
 351 }
 352 
 353 template <class ELT> int CBufferT <ELT> ::Pop(CBufferT<ELT> & buf)
 354 {
 355     int size, res = 1;
 356     res = res && Pop(*(ELT*)&size);
 357     buf.Restore(size);
 358 
 359     for (int i = size - 1; i >= 0; i--)
 360     {
 361         res = res && Pop(buf[i]);
 362     }
 363 
 364     return res;
 365 }
 366 
 367 template <class ELT> inline int CBufferT <ELT> ::Peek(ELT & el) const
 368 {
 369     if (CBufferRefT <ELT> ::m_nSize > 0)
 370     {
 371         el = CBufferRefT<ELT>::m_pBuffer[CBufferRefT <ELT> ::m_nSize - 1];
 372         return 1;
 373     }
 374     else
 375     {
 376         return 0;
 377     }
 378 }
 379 
 380 template <class ELT> const ELT * CBufferT <ELT> ::GetBuffer() const
 381 {
 382     static const ELT _def[] = { 0 }; return CBufferRefT<ELT>::m_pBuffer ? CBufferRefT<ELT>::m_pBuffer : _def;
 383 }
 384 
 385 template <class ELT> ELT * CBufferT <ELT> ::GetBuffer()
 386 {
 387     static const ELT _def[] = { 0 }; return CBufferRefT<ELT>::m_pBuffer ? CBufferRefT<ELT>::m_pBuffer : (ELT *)_def;
 388 }
 389 
 390 template <class ELT> ELT * CBufferT <ELT> ::Detach()
 391 {
 392     ELT * pBuffer = CBufferRefT<ELT>::m_pBuffer;
 393 
 394     CBufferRefT <ELT> ::m_pBuffer = 0;
 395     CBufferRefT <ELT> ::m_nSize = m_nMaxLength = 0;
 396 
 397     return pBuffer;
 398 }
 399 
 400 template <class ELT> void CBufferT <ELT> ::Release()
 401 {
 402     ELT * pBuffer = Detach();
 403 
 404     if (pBuffer != 0) free(pBuffer);
 405 }
 406 
 407 template <class ELT> void CBufferT <ELT> ::Prepare(int index, int fill)
 408 {
 409     int nNewSize = index + 1;
 410 
 411     // Realloc
 412     if (nNewSize > m_nMaxLength)
 413     {
 414         int nNewLength = m_nMaxLength;
 415 
 416         if (nNewLength < 8)
 417             nNewLength = 8;
 418 
 419         if (nNewSize > nNewLength)
 420             nNewLength *= 2;
 421 
 422         if (nNewSize > nNewLength)
 423         {
 424             nNewLength = nNewSize + 11;
 425             nNewLength -= nNewLength % 8;
 426         }
 427 
 428         CBufferRefT <ELT> ::m_pBuffer = (ELT *)realloc(CBufferRefT<ELT>::m_pBuffer, sizeof(ELT) * nNewLength);
 429         m_nMaxLength = nNewLength;
 430     }
 431 
 432     // size
 433     if (CBufferRefT <ELT> ::m_nSize < nNewSize)
 434     {
 435         memset(CBufferRefT<ELT>::m_pBuffer + CBufferRefT <ELT> ::m_nSize, fill, sizeof(ELT) * (nNewSize - CBufferRefT <ELT> ::m_nSize));
 436         CBufferRefT <ELT> ::m_nSize = nNewSize;
 437     }
 438 }
 439 
 440 template <class ELT> inline void CBufferT <ELT> ::Restore(int size)
 441 {
 442     SetMaxLength(size);
 443     CBufferRefT <ELT> ::m_nSize = size;
 444 }
 445 
 446 template <class ELT> CBufferT <ELT> :: ~CBufferT()
 447 {
 448     if (CBufferRefT<ELT>::m_pBuffer != 0) free(CBufferRefT<ELT>::m_pBuffer);
 449 }
 450 
 451 template <class T> class CSortedBufferT : public CBufferT <T>
 452 {
 453 public:
 454     CSortedBufferT(int reverse = 0);
 455     CSortedBufferT(int(*)(const void *, const void *));
 456 
 457 public:
 458     void Add(const T & rT);
 459     void Add(const T * pT, int nSize);
 460     int  Remove(const T & rT);
 461     void RemoveAll();
 462 
 463     void SortFreeze() { m_bSortFreezed = 1; }
 464     void SortUnFreeze();
 465 
 466 public:
 467     int  Find(const T & rT, int(*compare)(const void *, const void *) = 0) { return FindAs(*(T*)&rT, compare); }
 468     int  FindAs(const T & rT, int(*)(const void *, const void *) = 0);
 469     int  GetSize() const { return CBufferRefT<T>::m_nSize; }
 470     T & operator [] (int nIndex) { return CBufferT <T> :: operator [] (nIndex); }
 471 
 472 protected:
 473     int(*m_fncompare)(const void *, const void *);
 474     static int compareT(const void *, const void *);
 475     static int compareReverseT(const void *, const void *);
 476 
 477     int  m_bSortFreezed;
 478 };
 479 
 480 template <class T> CSortedBufferT <T> ::CSortedBufferT(int reverse)
 481 {
 482     m_fncompare = reverse ? compareReverseT : compareT;
 483     m_bSortFreezed = 0;
 484 }
 485 
 486 template <class T> CSortedBufferT <T> ::CSortedBufferT(int(*compare)(const void *, const void *))
 487 {
 488     m_fncompare = compare;
 489     m_bSortFreezed = 0;
 490 }
 491 
 492 template <class T> void CSortedBufferT <T> ::Add(const T & rT)
 493 {
 494     if (m_bSortFreezed != 0)
 495     {
 496         Append(rT);
 497         return;
 498     }
 499 
 500     int a = 0, b = CBufferRefT<T>::m_nSize - 1, c = CBufferRefT<T>::m_nSize / 2;
 501 
 502     while (a <= b)
 503     {
 504         int r = m_fncompare(&rT, &CBufferRefT<T>::m_pBuffer[c]);
 505 
 506         if (r < 0) b = c - 1;
 507         else if (r > 0) a = c + 1;
 508         else break;
 509 
 510         c = (a + b + 1) / 2;
 511     }
 512 
 513     Insert(c, rT);
 514 }
 515 
 516 template <class T> void CSortedBufferT <T> ::Add(const T * pT, int nSize)
 517 {
 518     Append(pT, nSize);
 519 
 520     if (m_bSortFreezed == 0)
 521     {
 522         qsort(CBufferRefT<T>::m_pBuffer, CBufferRefT<T>::m_nSize, sizeof(T), m_fncompare);
 523     }
 524 }
 525 
 526 template <class T> int CSortedBufferT <T> ::FindAs(const T & rT, int(*compare)(const void *, const void *))
 527 {
 528     const T * pT = (const T *)bsearch(&rT, CBufferRefT<T>::m_pBuffer, CBufferRefT<T>::m_nSize, sizeof(T), compare == 0 ? m_fncompare : compare);
 529 
 530     if (pT != NULL)
 531         return pT - CBufferRefT<T>::m_pBuffer;
 532     else
 533         return -1;
 534 }
 535 
 536 template <class T> int CSortedBufferT <T> ::Remove(const T & rT)
 537 {
 538     int pos = Find(rT);
 539     if (pos >= 0) CBufferT <T> ::Remove(pos);
 540     return pos;
 541 }
 542 
 543 template <class T> inline void CSortedBufferT <T> ::RemoveAll()
 544 {
 545     CBufferT<T>::Restore(0);
 546 }
 547 
 548 template <class T> void CSortedBufferT <T> ::SortUnFreeze()
 549 {
 550     if (m_bSortFreezed != 0)
 551     {
 552         m_bSortFreezed = 0;
 553         qsort(CBufferRefT<T>::m_pBuffer, CBufferRefT<T>::m_nSize, sizeof(T), m_fncompare);
 554     }
 555 }
 556 
 557 template <class T> int CSortedBufferT <T> ::compareT(const void * elem1, const void * elem2)
 558 {
 559     if (*(const T *)elem1 == *(const T *)elem2)
 560         return 0;
 561     else if (*(const T *)elem1 < *(const T *)elem2)
 562         return -1;
 563     else
 564         return 1;
 565 }
 566 
 567 template <class T> int CSortedBufferT <T> ::compareReverseT(const void * elem1, const void * elem2)
 568 {
 569     if (*(const T *)elem1 == *(const T *)elem2)
 570         return 0;
 571     else if (*(const T *)elem1 > *(const T *)elem2)
 572         return -1;
 573     else
 574         return 1;
 575 }
 576 
 577 //
 578 // Context
 579 //
 580 class CContext
 581 {
 582 public:
 583     CBufferT <int> m_stack;
 584     CBufferT <int> m_capturestack, m_captureindex;
 585 
 586 public:
 587     int    m_nCurrentPos;
 588     int    m_nBeginPos;
 589     int    m_nLastBeginPos;
 590     int    m_nParenZindex;
 591     int    m_nCursiveLimit;
 592 
 593     void * m_pMatchString;
 594     int    m_pMatchStringLength;
 595 };
 596 
 597 class CContextShot
 598 {
 599 public:
 600     CContextShot(CContext * pContext)
 601     {
 602         m_nCurrentPos = pContext->m_nCurrentPos;
 603         nsize = pContext->m_stack.GetSize();
 604         ncsize = pContext->m_capturestack.GetSize();
 605     }
 606 
 607     void Restore(CContext * pContext)
 608     {
 609         pContext->m_stack.Restore(nsize);
 610         pContext->m_capturestack.Restore(ncsize);
 611         pContext->m_nCurrentPos = m_nCurrentPos;
 612     }
 613 
 614 public:
 615     int m_nCurrentPos;
 616     int nsize;
 617     int ncsize;
 618 };
 619 
 620 //
 621 // Interface
 622 //
 623 class ElxInterface
 624 {
 625 public:
 626     virtual int Match(CContext * pContext) const = 0;
 627     virtual int MatchNext(CContext * pContext) const = 0;
 628 
 629 public:
 630     virtual ~ElxInterface() {};
 631 };
 632 
 633 //
 634 // Alternative
 635 //
 636 template <int x> class CAlternativeElxT : public ElxInterface
 637 {
 638 public:
 639     int Match(CContext * pContext) const;
 640     int MatchNext(CContext * pContext) const;
 641 
 642 public:
 643     CAlternativeElxT();
 644 
 645 public:
 646     CBufferT <ElxInterface *> m_elxlist;
 647 };
 648 
 649 typedef CAlternativeElxT <0> CAlternativeElx;
 650 
 651 //
 652 // Assert
 653 //
 654 template <int x> class CAssertElxT : public ElxInterface
 655 {
 656 public:
 657     int Match(CContext * pContext) const;
 658     int MatchNext(CContext * pContext) const;
 659 
 660 public:
 661     CAssertElxT(ElxInterface * pelx, int byes = 1);
 662 
 663 public:
 664     ElxInterface * m_pelx;
 665     int m_byes;
 666 };
 667 
 668 typedef CAssertElxT <0> CAssertElx;
 669 
 670 //
 671 // Back reference elx
 672 //
 673 template <class CHART> class CBackrefElxT : public ElxInterface
 674 {
 675 public:
 676     int Match(CContext * pContext) const;
 677     int MatchNext(CContext * pContext) const;
 678 
 679 public:
 680     CBackrefElxT(int nnumber, int brightleft, int bignorecase);
 681 
 682 public:
 683     int m_nnumber;
 684     int m_brightleft;
 685     int m_bignorecase;
 686 
 687     CBufferT <CHART> m_szNamed;
 688 };
 689 
 690 //
 691 // Implementation
 692 //
 693 template <class CHART> CBackrefElxT <CHART> ::CBackrefElxT(int nnumber, int brightleft, int bignorecase)
 694 {
 695     m_nnumber = nnumber;
 696     m_brightleft = brightleft;
 697     m_bignorecase = bignorecase;
 698 }
 699 
 700 template <class CHART> int CBackrefElxT <CHART> ::Match(CContext * pContext) const
 701 {
 702     // check number, for named
 703     if (m_nnumber < 0 || m_nnumber >= pContext->m_captureindex.GetSize()) return 0;
 704 
 705     int index = pContext->m_captureindex[m_nnumber];
 706     if (index < 0) return 0;
 707 
 708     // check enclosed
 709     int pos1 = pContext->m_capturestack[index + 1];
 710     int pos2 = pContext->m_capturestack[index + 2];
 711 
 712     if (pos2 < 0) pos2 = pContext->m_nCurrentPos;
 713 
 714     // info
 715     int lpos = pos1 < pos2 ? pos1 : pos2;
 716     int rpos = pos1 < pos2 ? pos2 : pos1;
 717     int slen = rpos - lpos;
 718 
 719     const CHART * pcsz = (const CHART *)pContext->m_pMatchString;
 720     int npos = pContext->m_nCurrentPos;
 721     int tlen = pContext->m_pMatchStringLength;
 722 
 723     // compare
 724     int bsucc;
 725     CBufferRefT <CHART> refstr(pcsz + lpos, slen);
 726 
 727     if (m_brightleft)
 728     {
 729         if (npos < slen)
 730             return 0;
 731 
 732         if (m_bignorecase)
 733             bsucc = !refstr.nCompareNoCase(pcsz + (npos - slen));
 734         else
 735             bsucc = !refstr.nCompare(pcsz + (npos - slen));
 736 
 737         if (bsucc)
 738         {
 739             pContext->m_stack.Push(npos);
 740             pContext->m_nCurrentPos -= slen;
 741         }
 742     }
 743     else
 744     {
 745         if (npos + slen > tlen)
 746             return 0;
 747 
 748         if (m_bignorecase)
 749             bsucc = !refstr.nCompareNoCase(pcsz + npos);
 750         else
 751             bsucc = !refstr.nCompare(pcsz + npos);
 752 
 753         if (bsucc)
 754         {
 755             pContext->m_stack.Push(npos);
 756             pContext->m_nCurrentPos += slen;
 757         }
 758     }
 759 
 760     return bsucc;
 761 }
 762 
 763 template <class CHART> int CBackrefElxT <CHART> ::MatchNext(CContext * pContext) const
 764 {
 765     int npos = 0;
 766 
 767     pContext->m_stack.Pop(npos);
 768     pContext->m_nCurrentPos = npos;
 769 
 770     return 0;
 771 }
 772 
 773 // RCHART
 774 #ifndef RCHART
 775 #define RCHART(ch) ((CHART)ch)
 776 #endif
 777 
 778 // BOUNDARY_TYPE
 779 enum BOUNDARY_TYPE
 780 {
 781     BOUNDARY_FILE_BEGIN, // begin of whole text
 782     BOUNDARY_FILE_END, // end of whole text
 783     BOUNDARY_FILE_END_N, // end of whole text, or before newline at the end
 784     BOUNDARY_LINE_BEGIN, // begin of line
 785     BOUNDARY_LINE_END, // end of line
 786     BOUNDARY_WORD_BEGIN, // begin of word
 787     BOUNDARY_WORD_END, // end of word
 788     BOUNDARY_WORD_EDGE
 789 };
 790 
 791 //
 792 // Boundary Elx
 793 //
 794 template <class CHART> class CBoundaryElxT : public ElxInterface
 795 {
 796 public:
 797     int Match(CContext * pContext) const;
 798     int MatchNext(CContext * pContext) const;
 799 
 800 public:
 801     CBoundaryElxT(int ntype, int byes = 1);
 802 
 803 protected:
 804     static int IsWordChar(CHART ch);
 805 
 806 public:
 807     int m_ntype;
 808     int m_byes;
 809 };
 810 
 811 //
 812 // Implementation
 813 //
 814 template <class CHART> CBoundaryElxT <CHART> ::CBoundaryElxT(int ntype, int byes)
 815 {
 816     m_ntype = ntype;
 817     m_byes = byes;
 818 }
 819 
 820 template <class CHART> int CBoundaryElxT <CHART> ::Match(CContext * pContext) const
 821 {
 822     const CHART * pcsz = (const CHART *)pContext->m_pMatchString;
 823     int npos = pContext->m_nCurrentPos;
 824     int tlen = pContext->m_pMatchStringLength;
 825 
 826     CHART chL = npos > 0 ? pcsz[npos - 1] : 0;
 827     CHART chR = npos < tlen ? pcsz[npos] : 0;
 828 
 829     int bsucc = 0;
 830 
 831     switch (m_ntype)
 832     {
 833     case BOUNDARY_FILE_BEGIN:
 834         bsucc = (npos <= 0);
 835         break;
 836 
 837     case BOUNDARY_FILE_END:
 838         bsucc = (npos >= tlen);
 839         break;
 840 
 841     case BOUNDARY_FILE_END_N:
 842         bsucc = (npos >= tlen) || (pcsz[tlen - 1] == RCHART('\n') && (npos == tlen - 1 || (pcsz[tlen - 2] == RCHART('\r') && npos == tlen - 2)));
 843         break;
 844 
 845     case BOUNDARY_LINE_BEGIN:
 846         bsucc = (npos <= 0) || (chL == RCHART('\n')) || ((chL == RCHART('\r')) && (chR != RCHART('\n')));
 847         break;
 848 
 849     case BOUNDARY_LINE_END:
 850         bsucc = (npos >= tlen) || (chR == RCHART('\r')) || ((chR == RCHART('\n')) && (chL != RCHART('\r')));
 851         break;
 852 
 853     case BOUNDARY_WORD_BEGIN:
 854         bsucc = !IsWordChar(chL) && IsWordChar(chR);
 855         break;
 856 
 857     case BOUNDARY_WORD_END:
 858         bsucc = IsWordChar(chL) && !IsWordChar(chR);
 859         break;
 860 
 861     case BOUNDARY_WORD_EDGE:
 862         bsucc = IsWordChar(chL) ? !IsWordChar(chR) : IsWordChar(chR);
 863         break;
 864     }
 865 
 866     return m_byes ? bsucc : !bsucc;
 867 }
 868 
 869 template <class CHART> int CBoundaryElxT <CHART> ::MatchNext(CContext *) const
 870 {
 871     return 0;
 872 }
 873 
 874 template <class CHART> inline int CBoundaryElxT <CHART> ::IsWordChar(CHART ch)
 875 {
 876     return (ch >= RCHART('A') && ch <= RCHART('Z')) || (ch >= RCHART('a') && ch <= RCHART('z')) || (ch >= RCHART('0') && ch <= RCHART('9')) || (ch == RCHART('_'));
 877 }
 878 
 879 //
 880 // Bracket
 881 //
 882 template <class CHART> class CBracketElxT : public ElxInterface
 883 {
 884 public:
 885     int Match(CContext * pContext) const;
 886     int MatchNext(CContext * pContext) const;
 887 
 888 public:
 889     CBracketElxT(int nnumber, int bright);
 890     static int CheckCaptureIndex(int & index, CContext * pContext, int number);
 891 
 892 public:
 893     int m_nnumber;
 894     int m_bright;
 895 
 896     CBufferT <CHART> m_szNamed;
 897 };
 898 
 899 template <class CHART> CBracketElxT <CHART> ::CBracketElxT(int nnumber, int bright)
 900 {
 901     m_nnumber = nnumber;
 902     m_bright = bright;
 903 }
 904 
 905 template <class CHART> inline int CBracketElxT <CHART> ::CheckCaptureIndex(int & index, CContext * pContext, int number)
 906 {
 907     if (index >= pContext->m_capturestack.GetSize())
 908         index = pContext->m_capturestack.GetSize() - 4;
 909 
 910     while (index >= 0)
 911     {
 912         if (pContext->m_capturestack[index] == number)
 913         {
 914             return 1;
 915         }
 916 
 917         index -= 4;
 918     }
 919 
 920 
 921     return 0;
 922 }
 923 
 924 //
 925 // capturestack[index+0] => Group number
 926 // capturestack[index+1] => Capture start pos
 927 // capturestack[index+2] => Capture end pos
 928 // capturestack[index+3] => Capture enclose z-index, zindex<0 means inner group with same name
 929 //
 930 template <class CHART> int CBracketElxT <CHART> ::Match(CContext * pContext) const
 931 {
 932     // check, for named
 933     if (m_nnumber < 0) return 0;
 934 
 935     if (!m_bright)
 936     {
 937         pContext->m_captureindex.Prepare(m_nnumber, -1);
 938         int index = pContext->m_captureindex[m_nnumber];
 939 
 940         // check
 941         if (CheckCaptureIndex(index, pContext, m_nnumber) && pContext->m_capturestack[index + 2] < 0)
 942         {
 943             pContext->m_capturestack[index + 3] --;
 944             return 1;
 945         }
 946 
 947         // save
 948         pContext->m_captureindex[m_nnumber] = pContext->m_capturestack.GetSize();
 949 
 950         pContext->m_capturestack.Push(m_nnumber);
 951         pContext->m_capturestack.Push(pContext->m_nCurrentPos);
 952         pContext->m_capturestack.Push(-1);
 953         pContext->m_capturestack.Push(0); // z-index
 954     }
 955     else
 956     {
 957         // check
 958         int index = pContext->m_captureindex[m_nnumber];
 959 
 960         if (CheckCaptureIndex(index, pContext, m_nnumber))
 961         {
 962             if (pContext->m_capturestack[index + 3] < 0) // check inner group with same name
 963             {
 964                 pContext->m_capturestack[index + 3] ++;
 965                 return 1;
 966             }
 967 
 968             // save
 969             pContext->m_capturestack[index + 2] = pContext->m_nCurrentPos;
 970             pContext->m_capturestack[index + 3] = pContext->m_nParenZindex++;
 971         }
 972     }
 973 
 974     return 1;
 975 }
 976 
 977 template <class CHART> int CBracketElxT <CHART> ::MatchNext(CContext * pContext) const
 978 {
 979     int index = pContext->m_captureindex[m_nnumber];
 980     if (!CheckCaptureIndex(index, pContext, m_nnumber))
 981     {
 982         return 0;
 983     }
 984 
 985     if (!m_bright)
 986     {
 987         if (pContext->m_capturestack[index + 3] < 0)
 988         {
 989             pContext->m_capturestack[index + 3] ++;
 990             return 0;
 991         }
 992 
 993         pContext->m_capturestack.Restore(pContext->m_capturestack.GetSize() - 4);
 994 
 995         // to find
 996         CheckCaptureIndex(index, pContext, m_nnumber);
 997 
 998         // new index
 999         pContext->m_captureindex[m_nnumber] = index;
1000     }
1001     else
1002     {
1003         if (pContext->m_capturestack[index + 2] >= 0)
1004         {
1005             pContext->m_capturestack[index + 2] = -1;
1006             pContext->m_capturestack[index + 3] = 0;
1007         }
1008         else
1009         {
1010             pContext->m_capturestack[index + 3] --;
1011         }
1012     }
1013 
1014     return 0;
1015 }
1016 
1017 //
1018 // Deletage
1019 //
1020 template <class CHART> class CDelegateElxT : public ElxInterface
1021 {
1022 public:
1023     int Match(CContext * pContext) const;
1024     int MatchNext(CContext * pContext) const;
1025 
1026 public:
1027     CDelegateElxT(int ndata = 0);
1028 
1029 public:
1030     ElxInterface * m_pelx;
1031     int m_ndata; // +0 : recursive to
1032                  // -3 : named recursive
1033 
1034     CBufferT <CHART> m_szNamed;
1035 };
1036 
1037 template <class CHART> CDelegateElxT <CHART> ::CDelegateElxT(int ndata)
1038 {
1039     m_pelx = 0;
1040     m_ndata = ndata;
1041 }
1042 
1043 template <class CHART> int CDelegateElxT <CHART> ::Match(CContext * pContext) const
1044 {
1045     if (m_pelx != 0)
1046     {
1047         if (pContext->m_nCursiveLimit > 0)
1048         {
1049             pContext->m_nCursiveLimit--;
1050             int result = m_pelx->Match(pContext);
1051             pContext->m_nCursiveLimit++;
1052             return result;
1053         }
1054         else
1055             return 0;
1056     }
1057     else
1058         return 1;
1059 }
1060 
1061 template <class CHART> int CDelegateElxT <CHART> ::MatchNext(CContext * pContext) const
1062 {
1063     if (m_pelx != 0)
1064         return m_pelx->MatchNext(pContext);
1065     else
1066         return 0;
1067 }
1068 
1069 //
1070 // Empty
1071 //
1072 template <int x> class CEmptyElxT : public ElxInterface
1073 {
1074 public:
1075     int Match(CContext * pContext) const;
1076     int MatchNext(CContext * pContext) const;
1077 
1078 public:
1079     CEmptyElxT();
1080 };
1081 
1082 typedef CEmptyElxT <0> CEmptyElx;
1083 
1084 //
1085 // Global
1086 //
1087 template <int x> class CGlobalElxT : public ElxInterface
1088 {
1089 public:
1090     int Match(CContext * pContext) const;
1091     int MatchNext(CContext * pContext) const;
1092 
1093 public:
1094     CGlobalElxT();
1095 };
1096 
1097 typedef CGlobalElxT <0> CGlobalElx;
1098 
1099 //
1100 // Repeat
1101 //
1102 template <int x> class CRepeatElxT : public ElxInterface
1103 {
1104 public:
1105     int Match(CContext * pContext) const;
1106     int MatchNext(CContext * pContext) const;
1107 
1108 public:
1109     CRepeatElxT(ElxInterface * pelx, int ntimes);
1110 
1111 protected:
1112     int MatchFixed(CContext * pContext) const;
1113     int MatchNextFixed(CContext * pContext) const;
1114     int MatchForward(CContext * pContext) const
1115     {
1116         CContextShot shot(pContext);
1117 
1118         if (!m_pelx->Match(pContext))
1119             return 0;
1120 
1121         if (pContext->m_nCurrentPos != shot.m_nCurrentPos)
1122             return 1;
1123 
1124         if (!m_pelx->MatchNext(pContext))
1125             return 0;
1126 
1127         if (pContext->m_nCurrentPos != shot.m_nCurrentPos)
1128             return 1;
1129 
1130         shot.Restore(pContext);
1131         return 0;
1132     }
1133 
1134 public:
1135     ElxInterface * m_pelx;
1136     int m_nfixed;
1137 };
1138 
1139 typedef CRepeatElxT <0> CRepeatElx;
1140 
1141 //
1142 // Greedy
1143 //
1144 template <int x> class CGreedyElxT : public CRepeatElxT <x>
1145 {
1146 public:
1147     int Match(CContext * pContext) const;
1148     int MatchNext(CContext * pContext) const;
1149 
1150 public:
1151     CGreedyElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);
1152 
1153 protected:
1154     int MatchVart(CContext * pContext) const;
1155     int MatchNextVart(CContext * pContext) const;
1156 
1157 public:
1158     int m_nvart;
1159 };
1160 
1161 typedef CGreedyElxT <0> CGreedyElx;
1162 
1163 //
1164 // Independent
1165 //
1166 template <int x> class CIndependentElxT : public ElxInterface
1167 {
1168 public:
1169     int Match(CContext * pContext) const;
1170     int MatchNext(CContext * pContext) const;
1171 
1172 public:
1173     CIndependentElxT(ElxInterface * pelx);
1174 
1175 public:
1176     ElxInterface * m_pelx;
1177 };
1178 
1179 typedef CIndependentElxT <0> CIndependentElx;
1180 
1181 //
1182 // List
1183 //
1184 template <int x> class CListElxT : public ElxInterface
1185 {
1186 public:
1187     int Match(CContext * pContext) const;
1188     int MatchNext(CContext * pContext) const;
1189 
1190 public:
1191     CListElxT(int brightleft);
1192 
1193 public:
1194     CBufferT <ElxInterface *> m_elxlist;
1195     int m_brightleft;
1196 };
1197 
1198 typedef CListElxT <0> CListElx;
1199 
1200 //
1201 // Posix Elx
1202 //
1203 template <class CHART> class CPosixElxT : public ElxInterface
1204 {
1205 public:
1206     int Match(CContext * pContext) const;
1207     int MatchNext(CContext * pContext) const;
1208 
1209 public:
1210     CPosixElxT(const char * posix, int brightleft);
1211 
1212 public:
1213     POSIX_FUNC m_posixfun;
1214     int m_brightleft;
1215     int m_byes;
1216 };
1217 
1218 //
1219 // Implementation
1220 //
1221 template <class CHART> CPosixElxT <CHART> ::CPosixElxT(const char * posix, int brightleft)
1222 {
1223     m_brightleft = brightleft;
1224 
1225     if (posix[1] == '^')
1226     {
1227         m_byes = 0;
1228         posix += 2;
1229     }
1230     else
1231     {
1232         m_byes = 1;
1233         posix += 1;
1234     }
1235 
1236     if (!strncmp(posix, "alnum:", 6)) m_posixfun = ::isalnum;
1237     else if (!strncmp(posix, "alpha:", 6)) m_posixfun = ::isalpha;
1238     else if (!strncmp(posix, "ascii:", 6)) m_posixfun = ::isascii;
1239     else if (!strncmp(posix, "cntrl:", 6)) m_posixfun = ::iscntrl;
1240     else if (!strncmp(posix, "digit:", 6)) m_posixfun = ::isdigit;
1241     else if (!strncmp(posix, "graph:", 6)) m_posixfun = ::isgraph;
1242     else if (!strncmp(posix, "lower:", 6)) m_posixfun = ::islower;
1243     else if (!strncmp(posix, "print:", 6)) m_posixfun = ::isprint;
1244     else if (!strncmp(posix, "punct:", 6)) m_posixfun = ::ispunct;
1245     else if (!strncmp(posix, "space:", 6)) m_posixfun = ::isspace;
1246     else if (!strncmp(posix, "upper:", 6)) m_posixfun = ::isupper;
1247     else if (!strncmp(posix, "xdigit:", 7)) m_posixfun = ::isxdigit;
1248     else if (!strncmp(posix, "blank:", 6)) m_posixfun = isblank;
1249     else                                  m_posixfun = 0;
1250 }
1251 
1252 inline int isblank(int c)
1253 {
1254     return c == 0x20 || c == '\t';
1255 }
1256 
1257 template <class CHART> int CPosixElxT <CHART> ::Match(CContext * pContext) const
1258 {
1259     if (m_posixfun == 0) return 0;
1260 
1261     int tlen = pContext->m_pMatchStringLength;
1262     int npos = pContext->m_nCurrentPos;
1263 
1264     // check
1265     int at = m_brightleft ? npos - 1 : npos;
1266     if (at < 0 || at >= tlen)
1267         return 0;
1268 
1269     CHART ch = ((const CHART *)pContext->m_pMatchString)[at];
1270 
1271     int bsucc = (*m_posixfun)(ch);
1272 
1273     if (!m_byes)
1274         bsucc = !bsucc;
1275 
1276     if (bsucc)
1277         pContext->m_nCurrentPos += m_brightleft ? -1 : 1;
1278 
1279     return bsucc;
1280 }
1281 
1282 template <class CHART> int CPosixElxT <CHART> ::MatchNext(CContext * pContext) const
1283 {
1284     pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
1285     return 0;
1286 }
1287 
1288 //
1289 // Possessive
1290 //
1291 template <int x> class CPossessiveElxT : public CGreedyElxT <x>
1292 {
1293 public:
1294     int Match(CContext * pContext) const;
1295     int MatchNext(CContext * pContext) const;
1296 
1297 public:
1298     CPossessiveElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);
1299 };
1300 
1301 typedef CPossessiveElxT <0> CPossessiveElx;
1302 
1303 //
1304 // Range Elx
1305 //
1306 template <class CHART> class CRangeElxT : public ElxInterface
1307 {
1308 public:
1309     int Match(CContext * pContext) const;
1310     int MatchNext(CContext * pContext) const;
1311 
1312 public:
1313     CRangeElxT(int brightleft, int byes);
1314 
1315 public:
1316     int IsContainChar(CHART ch) const;
1317 
1318 public:
1319     CBufferT <CHART> m_ranges;
1320     CBufferT <CHART> m_chars;
1321     CBufferT <ElxInterface *> m_embeds;
1322 
1323 public:
1324     int m_brightleft;
1325     int m_byes;
1326 };
1327 
1328 //
1329 // Implementation
1330 //
1331 template <class CHART> CRangeElxT <CHART> ::CRangeElxT(int brightleft, int byes)
1332 {
1333     m_brightleft = brightleft;
1334     m_byes = byes;
1335 }
1336 
1337 template <class CHART> int CRangeElxT <CHART> ::Match(CContext * pContext) const
1338 {
1339     int tlen = pContext->m_pMatchStringLength;
1340     int npos = pContext->m_nCurrentPos;
1341 
1342     // check
1343     int at = m_brightleft ? npos - 1 : npos;
1344     if (at < 0 || at >= tlen)
1345         return 0;
1346 
1347     CHART ch = ((const CHART *)pContext->m_pMatchString)[at];
1348     int bsucc = 0, i;
1349 
1350     // compare
1351     for (i = 0; !bsucc && i < m_ranges.GetSize(); i += 2)
1352     {
1353         if (m_ranges[i] <= ch && ch <= m_ranges[i + 1]) bsucc = 1;
1354     }
1355 
1356     for (i = 0; !bsucc && i < m_chars.GetSize(); i++)
1357     {
1358         if (m_chars[i] == ch) bsucc = 1;
1359     }
1360 
1361     for (i = 0; !bsucc && i < m_embeds.GetSize(); i++)
1362     {
1363         if (m_embeds[i]->Match(pContext))
1364         {
1365             pContext->m_nCurrentPos = npos;
1366             bsucc = 1;
1367         }
1368     }
1369 
1370     if (!m_byes)
1371         bsucc = !bsucc;
1372 
1373     if (bsucc)
1374         pContext->m_nCurrentPos += m_brightleft ? -1 : 1;
1375 
1376     return bsucc;
1377 }
1378 
1379 template <class CHART> int CRangeElxT <CHART> ::IsContainChar(CHART ch) const
1380 {
1381     int bsucc = 0, i;
1382 
1383     // compare
1384     for (i = 0; !bsucc && i < m_ranges.GetSize(); i += 2)
1385     {
1386         if (m_ranges[i] <= ch && ch <= m_ranges[i + 1]) bsucc = 1;
1387     }
1388 
1389     for (i = 0; !bsucc && i < m_chars.GetSize(); i++)
1390     {
1391         if (m_chars[i] == ch) bsucc = 1;
1392     }
1393 
1394     return bsucc;
1395 }
1396 
1397 template <class CHART> int CRangeElxT <CHART> ::MatchNext(CContext * pContext) const
1398 {
1399     pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
1400     return 0;
1401 }
1402 
1403 //
1404 // Reluctant
1405 //
1406 template <int x> class CReluctantElxT : public CRepeatElxT <x>
1407 {
1408 public:
1409     int Match(CContext * pContext) const;
1410     int MatchNext(CContext * pContext) const;
1411 
1412 public:
1413     CReluctantElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);
1414 
1415 protected:
1416     int MatchVart(CContext * pContext) const;
1417     int MatchNextVart(CContext * pContext) const;
1418 
1419 public:
1420     int m_nvart;
1421 };
1422 
1423 typedef CReluctantElxT <0> CReluctantElx;
1424 
1425 //
1426 // String Elx
1427 //
1428 template <class CHART> class CStringElxT : public ElxInterface
1429 {
1430 public:
1431     int Match(CContext * pContext) const;
1432     int MatchNext(CContext * pContext) const;
1433 
1434 public:
1435     CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase);
1436 
1437 public:
1438     CBufferT <CHART> m_szPattern;
1439     int m_brightleft;
1440     int m_bignorecase;
1441 };
1442 
1443 //
1444 // Implementation
1445 //
1446 template <class CHART> CStringElxT <CHART> ::CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase) : m_szPattern(fixed, nlength)
1447 {
1448     m_brightleft = brightleft;
1449     m_bignorecase = bignorecase;
1450 }
1451 
1452 template <class CHART> int CStringElxT <CHART> ::Match(CContext * pContext) const
1453 {
1454     const CHART * pcsz = (const CHART *)pContext->m_pMatchString;
1455     int npos = pContext->m_nCurrentPos;
1456     int tlen = pContext->m_pMatchStringLength;
1457     int slen = m_szPattern.GetSize();
1458 
1459     int bsucc;
1460 
1461     if (m_brightleft)
1462     {
1463         if (npos < slen)
1464             return 0;
1465 
1466         if (m_bignorecase)
1467             bsucc = !m_szPattern.nCompareNoCase(pcsz + (npos - slen));
1468         else
1469             bsucc = !m_szPattern.nCompare(pcsz + (npos - slen));
1470 
1471         if (bsucc)
1472             pContext->m_nCurrentPos -= slen;
1473     }
1474     else
1475     {
1476         if (npos + slen > tlen)
1477             return 0;
1478 
1479         if (m_bignorecase)
1480             bsucc = !m_szPattern.nCompareNoCase(pcsz + npos);
1481         else
1482             bsucc = !m_szPattern.nCompare(pcsz + npos);
1483 
1484         if (bsucc)
1485             pContext->m_nCurrentPos += slen;
1486     }
1487 
1488     return bsucc;
1489 }
1490 
1491 template <class CHART> int CStringElxT <CHART> ::MatchNext(CContext * pContext) const
1492 {
1493     int slen = m_szPattern.GetSize();
1494 
1495     if (m_brightleft)
1496         pContext->m_nCurrentPos += slen;
1497     else
1498         pContext->m_nCurrentPos -= slen;
1499 
1500     return 0;
1501 }
1502 
1503 //
1504 // CConditionElx
1505 //
1506 template <class CHART> class CConditionElxT : public ElxInterface
1507 {
1508 public:
1509     int Match(CContext * pContext) const;
1510     int MatchNext(CContext * pContext) const;
1511 
1512 public:
1513     CConditionElxT();
1514 
1515 public:
1516     // backref condition
1517     int m_nnumber;
1518     CBufferT <CHART> m_szNamed;
1519 
1520     // elx condition
1521     ElxInterface * m_pelxask;
1522 
1523     // selection
1524     ElxInterface * m_pelxyes, *m_pelxno;
1525 };
1526 
1527 template <class CHART> CConditionElxT <CHART> ::CConditionElxT()
1528 {
1529     m_nnumber = -1;
1530 }
1531 
1532 template <class CHART> int CConditionElxT <CHART> ::Match(CContext * pContext) const
1533 {
1534     // status
1535     int nbegin = pContext->m_nCurrentPos;
1536     int nsize = pContext->m_stack.GetSize();
1537     int ncsize = pContext->m_capturestack.GetSize();
1538 
1539     // condition result
1540     int condition_yes = 0;
1541 
1542     // backref type
1543     if (m_nnumber >= 0)
1544     {
1545         do
1546         {
1547             if (m_nnumber >= pContext->m_captureindex.GetSize()) break;
1548 
1549             int index = pContext->m_captureindex[m_nnumber];
1550             if (index < 0) break;
1551 
1552             // else valid
1553             condition_yes = 1;
1554         } while (0);
1555     }
1556     else
1557     {
1558         if (m_pelxask == 0)
1559             condition_yes = 1;
1560         else
1561             condition_yes = m_pelxask->Match(pContext);
1562 
1563         pContext->m_stack.Restore(nsize);
1564         pContext->m_nCurrentPos = nbegin;
1565     }
1566 
1567     // elx result
1568     int bsucc;
1569     if (condition_yes)
1570         bsucc = m_pelxyes == 0 ? 1 : m_pelxyes->Match(pContext);
1571     else
1572         bsucc = m_pelxno == 0 ? 1 : m_pelxno->Match(pContext);
1573 
1574     if (bsucc)
1575     {
1576         pContext->m_stack.Push(ncsize);
1577         pContext->m_stack.Push(condition_yes);
1578     }
1579     else
1580     {
1581         pContext->m_capturestack.Restore(ncsize);
1582     }
1583 
1584     return bsucc;
1585 }
1586 
1587 template <class CHART> int CConditionElxT <CHART> ::MatchNext(CContext * pContext) const
1588 {
1589     // pop
1590     int ncsize, condition_yes;
1591 
1592     pContext->m_stack.Pop(condition_yes);
1593     pContext->m_stack.Pop(ncsize);
1594 
1595     // elx result
1596     int bsucc;
1597     if (condition_yes)
1598         bsucc = m_pelxyes == 0 ? 0 : m_pelxyes->MatchNext(pContext);
1599     else
1600         bsucc = m_pelxno == 0 ? 0 : m_pelxno->MatchNext(pContext);
1601 
1602     if (bsucc)
1603     {
1604         pContext->m_stack.Push(ncsize);
1605         pContext->m_stack.Push(condition_yes);
1606     }
1607     else
1608     {
1609         pContext->m_capturestack.Restore(ncsize);
1610     }
1611 
1612     return bsucc;
1613 }
1614 
1615 //
1616 // MatchResult
1617 //
1618 template <int x> class MatchResultT
1619 {
1620 public:
1621     int IsMatched() const;
1622 
1623 public:
1624     int GetStart() const;
1625     int GetEnd() const;
1626 
1627 public:
1628     int MaxGroupNumber() const;
1629     int GetGroupStart(int nGroupNumber) const;
1630     int GetGroupEnd(int nGroupNumber) const;
1631 
1632 public:
1633     MatchResultT(const MatchResultT <x> & from) { *this = from; }
1634     MatchResultT(CContext * pContext = 0, int nMaxNumber = -1);
1635     MatchResultT <x> & operator = (const MatchResultT <x> &);
1636     inline operator int() const { return IsMatched(); }
1637 
1638 public:
1639     CBufferT <int> m_result;
1640 };
1641 
1642 typedef MatchResultT <0> MatchResult;
1643 
1644 // Stocked Elx IDs
1645 enum STOCKELX_ID_DEFINES
1646 {
1647     STOCKELX_EMPTY = 0,
1648 
1649     ///////////////////////
1650 
1651     STOCKELX_DOT_ALL,
1652     STOCKELX_DOT_NOT_ALL,
1653 
1654     STOCKELX_WORD,
1655     STOCKELX_WORD_NOT,
1656 
1657     STOCKELX_SPACE,
1658     STOCKELX_SPACE_NOT,
1659 
1660     STOCKELX_DIGITAL,
1661     STOCKELX_DIGITAL_NOT,
1662 
1663     //////////////////////
1664 
1665     STOCKELX_DOT_ALL_RIGHTLEFT,
1666     STOCKELX_DOT_NOT_ALL_RIGHTLEFT,
1667 
1668     STOCKELX_WORD_RIGHTLEFT,
1669     STOCKELX_WORD_RIGHTLEFT_NOT,
1670 
1671     STOCKELX_SPACE_RIGHTLEFT,
1672     STOCKELX_SPACE_RIGHTLEFT_NOT,
1673 
1674     STOCKELX_DIGITAL_RIGHTLEFT,
1675     STOCKELX_DIGITAL_RIGHTLEFT_NOT,
1676 
1677     /////////////////////
1678 
1679     STOCKELX_COUNT
1680 };
1681 
1682 // REGEX_FLAGS
1683 #ifndef _REGEX_FLAGS_DEFINED
1684 enum REGEX_FLAGS
1685 {
1686     NO_FLAG = 0,
1687     SINGLELINE = 0x01,
1688     MULTILINE = 0x02,
1689     GLOBAL = 0x04,
1690     IGNORECASE = 0x08,
1691     RIGHTTOLEFT = 0x10,
1692     EXTENDED = 0x20
1693 };
1694 #define _REGEX_FLAGS_DEFINED
1695 #endif
1696 
1697 //
1698 // Builder T
1699 //
1700 template <class CHART> class CBuilderT
1701 {
1702 public:
1703     typedef CDelegateElxT  <CHART> CDelegateElx;
1704     typedef CBracketElxT   <CHART> CBracketElx;
1705     typedef CBackrefElxT   <CHART> CBackrefElx;
1706     typedef CConditionElxT <CHART> CConditionElx;
1707 
1708     // Methods
1709 public:
1710     ElxInterface * Build(const CBufferRefT <CHART> & pattern, int flags);
1711     int GetNamedNumber(const CBufferRefT <CHART> & named) const;
1712     void Clear();
1713 
1714 public:
1715     CBuilderT();
1716     ~CBuilderT();
1717 
1718     // Public Attributes
1719 public:
1720     ElxInterface * m_pTopElx;
1721     int            m_nFlags;
1722     int            m_nMaxNumber;
1723     int            m_nNextNamed;
1724     int            m_nGroupCount;
1725 
1726     CBufferT <ElxInterface  *> m_objlist;
1727     CBufferT <ElxInterface  *> m_grouplist;
1728     CBufferT <CDelegateElx  *> m_recursivelist;
1729     CBufferT <CListElx      *> m_namedlist;
1730     CBufferT <CBackrefElx   *> m_namedbackreflist;
1731     CBufferT <CConditionElx *> m_namedconditionlist;
1732 
1733     // CHART_INFO
1734 protected:
1735     struct CHART_INFO
1736     {
1737     public:
1738         CHART ch;
1739         int   type;
1740         int   pos;
1741         int   len;
1742 
1743     public:
1744         CHART_INFO(CHART c, int t, int p = 0, int l = 0) { ch = c; type = t; pos = p; len = l; }
1745         inline int operator == (const CHART_INFO & ci) { return ch == ci.ch && type == ci.type; }
1746         inline int operator != (const CHART_INFO & ci) { return !operator == (ci); }
1747     };
1748 
1749 protected:
1750     static unsigned int Hex2Int(const CHART * pcsz, int length, int & used);
1751     static int ReadDec(char * & str, unsigned int & dec);
1752     void MoveNext();
1753     int  GetNext2();
1754 
1755     ElxInterface * BuildAlternative(int vaflags);
1756     ElxInterface * BuildList(int & flags);
1757     ElxInterface * BuildRepeat(int & flags);
1758     ElxInterface * BuildSimple(int & flags);
1759     ElxInterface * BuildCharset(int & flags);
1760     ElxInterface * BuildRecursive(int & flags);
1761     ElxInterface * BuildBoundary(int & flags);
1762     ElxInterface * BuildBackref(int & flags);
1763 
1764     ElxInterface * GetStockElx(int nStockId);
1765     ElxInterface * Keep(ElxInterface * pElx);
1766 
1767     // Private Attributes
1768 protected:
1769     CBufferRefT <CHART> m_pattern;
1770     CHART_INFO prev, curr, next, nex2;
1771     int m_nNextPos;
1772     int m_nCharsetDepth;
1773     int m_bQuoted;
1774     POSIX_FUNC m_quote_fun;
1775 
1776     // Backup current pos
1777     struct Snapshot
1778     {
1779         CHART_INFO prev, curr, next, nex2;
1780         int m_nNextPos;
1781         int m_nCharsetDepth;
1782         int m_bQuoted;
1783         POSIX_FUNC m_quote_fun;
1784         Snapshot() :prev(0, 0), curr(0, 0), next(0, 0), nex2(0, 0) {}
1785     };
1786     void Backup(Snapshot * pdata) { memcpy(pdata, &prev, sizeof(Snapshot)); }
1787     void Restore(Snapshot * pdata) { memcpy(&prev, pdata, sizeof(Snapshot)); }
1788 
1789     ElxInterface * m_pStockElxs[STOCKELX_COUNT];
1790 };
1791 
1792 //
1793 // Implementation
1794 //
1795 template <class CHART> CBuilderT <CHART> ::CBuilderT() : m_pattern(0, 0), prev(0, 0), curr(0, 0), next(0, 0), nex2(0, 0)
1796 {
1797     Clear();
1798 }
1799 
1800 template <class CHART> CBuilderT <CHART> :: ~CBuilderT()
1801 {
1802     Clear();
1803 }
1804 
1805 template <class CHART> int CBuilderT <CHART> ::GetNamedNumber(const CBufferRefT <CHART> & named) const
1806 {
1807     for (int i = 0; i < m_namedlist.GetSize(); i++)
1808     {
1809         if (!((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_szNamed.CompareNoCase(named))
1810             return ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_nnumber;
1811     }
1812 
1813     return -3;
1814 }
1815 
1816 template <class CHART> ElxInterface * CBuilderT <CHART> ::Build(const CBufferRefT <CHART> & pattern, int flags)
1817 {
1818     // init
1819     m_pattern = pattern;
1820     m_nNextPos = 0;
1821     m_nCharsetDepth = 0;
1822     m_nMaxNumber = 0;
1823     m_nNextNamed = 0;
1824     m_nFlags = flags;
1825     m_bQuoted = 0;
1826     m_quote_fun = 0;
1827 
1828     m_grouplist.Restore(0);
1829     m_recursivelist.Restore(0);
1830     m_namedlist.Restore(0);
1831     m_namedbackreflist.Restore(0);
1832     m_namedconditionlist.Restore(0);
1833 
1834     int i;
1835     for (i = 0; i < 3; i++) MoveNext();
1836 
1837     // build
1838     m_pTopElx = BuildAlternative(flags);
1839 
1840     // group 0
1841     m_grouplist.Prepare(0);
1842     m_grouplist[0] = m_pTopElx;
1843 
1844     // append named to unnamed
1845     m_nGroupCount = m_grouplist.GetSize();
1846 
1847     m_grouplist.Prepare(m_nMaxNumber + m_namedlist.GetSize());
1848 
1849     for (i = 0; i < m_namedlist.GetSize(); i++)
1850     {
1851         CBracketElx * pleft = (CBracketElx *)m_namedlist[i]->m_elxlist[0];
1852         CBracketElx * pright = (CBracketElx *)m_namedlist[i]->m_elxlist[2];
1853 
1854         // append
1855         m_grouplist[m_nGroupCount++] = m_namedlist[i];
1856 
1857         if (pleft->m_nnumber > 0)
1858             continue;
1859 
1860         // same name
1861         int find_same_name = GetNamedNumber(pleft->m_szNamed);
1862         if (find_same_name >= 0)
1863         {
1864             pleft->m_nnumber = find_same_name;
1865             pright->m_nnumber = find_same_name;
1866         }
1867         else
1868         {
1869             m_nMaxNumber++;
1870 
1871             pleft->m_nnumber = m_nMaxNumber;
1872             pright->m_nnumber = m_nMaxNumber;
1873         }
1874     }
1875 
1876     for (i = 1; i < m_nGroupCount; i++)
1877     {
1878         CBracketElx * pleft = (CBracketElx *)((CListElx*)m_grouplist[i])->m_elxlist[0];
1879 
1880         if (pleft->m_nnumber > m_nMaxNumber)
1881             m_nMaxNumber = pleft->m_nnumber;
1882     }
1883 
1884     // connect recursive
1885     for (i = 0; i < m_recursivelist.GetSize(); i++)
1886     {
1887         if (m_recursivelist[i]->m_ndata == -3)
1888             m_recursivelist[i]->m_ndata = GetNamedNumber(m_recursivelist[i]->m_szNamed);
1889 
1890         if (m_recursivelist[i]->m_ndata >= 0 && m_recursivelist[i]->m_ndata <= m_nMaxNumber)
1891         {
1892             if (m_recursivelist[i]->m_ndata == 0)
1893                 m_recursivelist[i]->m_pelx = m_pTopElx;
1894             else for (int j = 1; j < m_grouplist.GetSize(); j++)
1895             {
1896                 if (m_recursivelist[i]->m_ndata == ((CBracketElx *)((CListElx*)m_grouplist[j])->m_elxlist[0])->m_nnumber)
1897                 {
1898                     m_recursivelist[i]->m_pelx = m_grouplist[j];
1899                     break;
1900                 }
1901             }
1902         }
1903     }
1904 
1905     // named backref
1906     for (i = 0; i < m_namedbackreflist.GetSize(); i++)
1907     {
1908         m_namedbackreflist[i]->m_nnumber = GetNamedNumber(m_namedbackreflist[i]->m_szNamed);
1909     }
1910 
1911     // named condition
1912     for (i = 0; i < m_namedconditionlist.GetSize(); i++)
1913     {
1914         int nn = GetNamedNumber(m_namedconditionlist[i]->m_szNamed);
1915         if (nn >= 0)
1916         {
1917             m_namedconditionlist[i]->m_nnumber = nn;
1918             m_namedconditionlist[i]->m_pelxask = 0;
1919         }
1920     }
1921 
1922     return m_pTopElx;
1923 }
1924 
1925 template <class CHART> void CBuilderT <CHART> ::Clear()
1926 {
1927     for (int i = 0; i < m_objlist.GetSize(); i++)
1928     {
1929         delete m_objlist[i];
1930     }
1931 
1932     m_objlist.Restore(0);
1933     m_pTopElx = 0;
1934     m_nMaxNumber = 0;
1935 
1936     memset(m_pStockElxs, 0, sizeof(m_pStockElxs));
1937 }
1938 
1939 //
1940 // hex to int
1941 //
1942 template <class CHART> unsigned int CBuilderT <CHART> ::Hex2Int(const CHART * pcsz, int length, int & used)
1943 {
1944     unsigned int result = 0;
1945     int & i = used;
1946 
1947     for (i = 0; i < length; i++)
1948     {
1949         if (pcsz[i] >= RCHART('0') && pcsz[i] <= RCHART('9'))
1950             result = (result << 4) + (pcsz[i] - RCHART('0'));
1951         else if (pcsz[i] >= RCHART('A') && pcsz[i] <= RCHART('F'))
1952             result = (result << 4) + (0x0A + (pcsz[i] - RCHART('A')));
1953         else if (pcsz[i] >= RCHART('a') && pcsz[i] <= RCHART('f'))
1954             result = (result << 4) + (0x0A + (pcsz[i] - RCHART('a')));
1955         else
1956             break;
1957     }
1958 
1959     return result;
1960 }
1961 
1962 template <class CHART> inline ElxInterface * CBuilderT <CHART> ::Keep(ElxInterface * pelx)
1963 {
1964     m_objlist.Push(pelx);
1965     return pelx;
1966 }
1967 
1968 template <class CHART> void CBuilderT <CHART> ::MoveNext()
1969 {
1970     // forwards
1971     prev = curr;
1972     curr = next;
1973     next = nex2;
1974 
1975     // get nex2
1976     while (!GetNext2()) {};
1977 }
1978 
1979 template <class CHART> int CBuilderT <CHART> ::GetNext2()
1980 {
1981     // check length
1982     if (m_nNextPos >= m_pattern.GetSize())
1983     {
1984         nex2 = CHART_INFO(0, 1, m_nNextPos, 0);
1985         return 1;
1986     }
1987 
1988     int   delta = 1;
1989     CHART ch = m_pattern[m_nNextPos];
1990 
1991     // if quoted
1992     if (m_bQuoted)
1993     {
1994         if (ch == RCHART('\\'))
1995         {
1996             if (m_pattern[m_nNextPos + 1] == RCHART('E'))
1997             {
1998                 m_quote_fun = 0;
1999                 m_bQuoted = 0;
2000                 m_nNextPos += 2;
2001                 return 0;
2002             }
2003         }
2004 
2005         if (m_quote_fun != 0)
2006             nex2 = CHART_INFO((CHART)(*m_quote_fun)((int)ch), 0, m_nNextPos, delta);
2007         else
2008             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2009 
2010         m_nNextPos += delta;
2011 
2012         return 1;
2013     }
2014 
2015     // common
2016     switch (ch)
2017     {
2018     case RCHART('\\'):
2019     {
2020         CHART ch1 = m_pattern[m_nNextPos + 1];
2021 
2022         // backref
2023         if (ch1 >= RCHART('0') && ch1 <= RCHART('9'))
2024         {
2025             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2026             break;
2027         }
2028 
2029         // escape
2030         delta = 2;
2031 
2032         switch (ch1)
2033         {
2034         case RCHART('A'):
2035         case RCHART('Z'):
2036         case RCHART('z'):
2037         case RCHART('w'):
2038         case RCHART('W'):
2039         case RCHART('s'):
2040         case RCHART('S'):
2041         case RCHART('B'):
2042         case RCHART('d'):
2043         case RCHART('D'):
2044         case RCHART('k'):
2045         case RCHART('g'):
2046             nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
2047             break;
2048 
2049         case RCHART('b'):
2050             if (m_nCharsetDepth > 0)
2051                 nex2 = CHART_INFO('\b', 0, m_nNextPos, delta);
2052             else
2053                 nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
2054             break;
2055 
2056             /*
2057             case RCHART('<'):
2058             case RCHART('>'):
2059             if(m_nCharsetDepth > 0)
2060             nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
2061             else
2062             nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
2063             break;
2064             */
2065 
2066         case RCHART('x'):
2067             if (m_pattern[m_nNextPos + 2] != '{')
2068             {
2069                 int red = 0;
2070                 unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 2, red);
2071 
2072                 delta += red;
2073 
2074                 if (red > 0)
2075                     nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
2076                 else
2077                     nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
2078 
2079                 break;
2080             }
2081 
2082         case RCHART('u'):
2083             if (m_pattern[m_nNextPos + 2] != '{')
2084             {
2085                 int red = 0;
2086                 unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 4, red);
2087 
2088                 delta += red;
2089 
2090                 if (red > 0)
2091                     nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
2092                 else
2093                     nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
2094             }
2095             else
2096             {
2097                 int red = 0;
2098                 unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 3, sizeof(int) * 2, red);
2099 
2100                 delta += red;
2101 
2102                 while (m_nNextPos + delta < m_pattern.GetSize() && m_pattern.At(m_nNextPos + delta) != RCHART('}'))
2103                     delta++;
2104 
2105                 delta++; // skip '}'
2106 
2107                 nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
2108             }
2109             break;
2110 
2111         case RCHART('a'): nex2 = CHART_INFO(RCHART('\a'), 0, m_nNextPos, delta); break;
2112         case RCHART('f'): nex2 = CHART_INFO(RCHART('\f'), 0, m_nNextPos, delta); break;
2113         case RCHART('n'): nex2 = CHART_INFO(RCHART('\n'), 0, m_nNextPos, delta); break;
2114         case RCHART('r'): nex2 = CHART_INFO(RCHART('\r'), 0, m_nNextPos, delta); break;
2115         case RCHART('t'): nex2 = CHART_INFO(RCHART('\t'), 0, m_nNextPos, delta); break;
2116         case RCHART('v'): nex2 = CHART_INFO(RCHART('\v'), 0, m_nNextPos, delta); break;
2117         case RCHART('e'): nex2 = CHART_INFO(RCHART(27), 0, m_nNextPos, delta); break;
2118 
2119         case RCHART('G'):  // skip '\G'
2120             if (m_nCharsetDepth > 0)
2121             {
2122                 m_nNextPos += 2;
2123                 return 0;
2124             }
2125             else
2126             {
2127                 nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
2128                 break;
2129             }
2130 
2131         case RCHART('L'):
2132             if (!m_quote_fun) m_quote_fun = ::tolower;
2133 
2134         case RCHART('U'):
2135             if (!m_quote_fun) m_quote_fun = ::toupper;
2136 
2137         case RCHART('Q'):
2138         {
2139             m_bQuoted = 1;
2140             m_nNextPos += 2;
2141             return 0;
2142         }
2143 
2144         case RCHART('E'):
2145         {
2146             m_quote_fun = 0;
2147             m_bQuoted = 0;
2148             m_nNextPos += 2;
2149             return 0;
2150         }
2151 
2152         case 0:
2153             if (m_nNextPos + 1 >= m_pattern.GetSize())
2154             {
2155                 delta = 1;
2156                 nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2157             }
2158             else
2159                 nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); // common '\0' char
2160             break;
2161 
2162         default:
2163             nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
2164             break;
2165         }
2166     }
2167     break;
2168 
2169     case RCHART('*'):
2170     case RCHART('+'):
2171     case RCHART('?'):
2172     case RCHART('.'):
2173     case RCHART('{'):
2174     case RCHART('}'):
2175     case RCHART(')'):
2176     case RCHART('|'):
2177     case RCHART('$'):
2178         if (m_nCharsetDepth > 0)
2179             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2180         else
2181             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2182         break;
2183 
2184     case RCHART('-'):
2185         if (m_nCharsetDepth > 0)
2186             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2187         else
2188             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2189         break;
2190 
2191     case RCHART('('):
2192     {
2193         CHART ch1 = m_pattern[m_nNextPos + 1];
2194         CHART ch2 = m_pattern[m_nNextPos + 2];
2195 
2196         // skip remark
2197         if (ch1 == RCHART('?') && ch2 == RCHART('#'))
2198         {
2199             m_nNextPos += 2;
2200             while (m_nNextPos < m_pattern.GetSize())
2201             {
2202                 if (m_pattern[m_nNextPos] == RCHART(')'))
2203                     break;
2204 
2205                 m_nNextPos++;
2206             }
2207 
2208             if (m_pattern[m_nNextPos] == RCHART(')'))
2209             {
2210                 m_nNextPos++;
2211 
2212                 // get next nex2
2213                 return 0;
2214             }
2215         }
2216         else
2217         {
2218             if (m_nCharsetDepth > 0)
2219                 nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2220             else
2221                 nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2222         }
2223     }
2224     break;
2225 
2226     case RCHART('#'):
2227         if (m_nFlags & EXTENDED)
2228         {
2229             // skip remark
2230             m_nNextPos++;
2231 
2232             while (m_nNextPos < m_pattern.GetSize())
2233             {
2234                 if (m_pattern[m_nNextPos] == RCHART('\n') || m_pattern[m_nNextPos] == RCHART('\r'))
2235                     break;
2236 
2237                 m_nNextPos++;
2238             }
2239 
2240             // get next nex2
2241             return 0;
2242         }
2243         else
2244         {
2245             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2246         }
2247         break;
2248 
2249     case RCHART(' '):
2250     case RCHART('\f'):
2251     case RCHART('\n'):
2252     case RCHART('\r'):
2253     case RCHART('\t'):
2254     case RCHART('\v'):
2255         if (m_nFlags & EXTENDED)
2256         {
2257             m_nNextPos++;
2258 
2259             // get next nex2
2260             return 0;
2261         }
2262         else
2263         {
2264             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2265         }
2266         break;
2267 
2268     case RCHART('['):
2269         if (m_nCharsetDepth == 0 || m_pattern.At(m_nNextPos + 1, 0) == RCHART(':'))
2270         {
2271             m_nCharsetDepth++;
2272             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2273         }
2274         else
2275         {
2276             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2277         }
2278         break;
2279 
2280     case RCHART(']'):
2281         if (m_nCharsetDepth > 0)
2282         {
2283             m_nCharsetDepth--;
2284             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2285         }
2286         else
2287         {
2288             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2289         }
2290         break;
2291 
2292     case RCHART(':'):
2293         if (next == CHART_INFO(RCHART('['), 1))
2294             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2295         else
2296             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2297         break;
2298 
2299     case RCHART('^'):
2300         if (m_nCharsetDepth == 0 || next == CHART_INFO(RCHART('['), 1) || (curr == CHART_INFO(RCHART('['), 1) && next == CHART_INFO(RCHART(':'), 1)))
2301             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
2302         else
2303             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2304         break;
2305 
2306     case 0:
2307         if (m_nNextPos >= m_pattern.GetSize())
2308             nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); // end of string
2309         else
2310             nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); // common '\0' char
2311         break;
2312 
2313     default:
2314         nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
2315         break;
2316     }
2317 
2318     m_nNextPos += delta;
2319 
2320     return 1;
2321 }
2322 
2323 template <class CHART> ElxInterface * CBuilderT <CHART> ::GetStockElx(int nStockId)
2324 {
2325     ElxInterface ** pStockElxs = m_pStockElxs;
2326 
2327     // check
2328     if (nStockId < 0 || nStockId >= STOCKELX_COUNT)
2329         return GetStockElx(0);
2330 
2331     // create if no
2332     if (pStockElxs[nStockId] == 0)
2333     {
2334         switch (nStockId)
2335         {
2336         case STOCKELX_EMPTY:
2337             pStockElxs[nStockId] = Keep(new CEmptyElx());
2338             break;
2339 
2340         case STOCKELX_WORD:
2341         {
2342             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 1));
2343 
2344             pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
2345             pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
2346             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2347             pRange->m_chars.Push(RCHART('_'));
2348 
2349             pStockElxs[nStockId] = pRange;
2350         }
2351         break;
2352 
2353         case STOCKELX_WORD_NOT:
2354         {
2355             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 0));
2356 
2357             pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
2358             pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
2359             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2360             pRange->m_chars.Push(RCHART('_'));
2361 
2362             pStockElxs[nStockId] = pRange;
2363         }
2364         break;
2365 
2366         case STOCKELX_DOT_ALL:
2367             pStockElxs[nStockId] = Keep(new CRangeElxT <CHART>(0, 0));
2368             break;
2369 
2370         case STOCKELX_DOT_NOT_ALL:
2371         {
2372             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 0));
2373 
2374             pRange->m_chars.Push(RCHART('\n'));
2375 
2376             pStockElxs[nStockId] = pRange;
2377         }
2378         break;
2379 
2380         case STOCKELX_SPACE:
2381         {
2382             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 1));
2383 
2384             pRange->m_chars.Push(RCHART(' '));
2385             pRange->m_chars.Push(RCHART('\t'));
2386             pRange->m_chars.Push(RCHART('\r'));
2387             pRange->m_chars.Push(RCHART('\n'));
2388 
2389             pStockElxs[nStockId] = pRange;
2390         }
2391         break;
2392 
2393         case STOCKELX_SPACE_NOT:
2394         {
2395             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 0));
2396 
2397             pRange->m_chars.Push(RCHART(' '));
2398             pRange->m_chars.Push(RCHART('\t'));
2399             pRange->m_chars.Push(RCHART('\r'));
2400             pRange->m_chars.Push(RCHART('\n'));
2401 
2402             pStockElxs[nStockId] = pRange;
2403         }
2404         break;
2405 
2406         case STOCKELX_DIGITAL:
2407         {
2408             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 1));
2409 
2410             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2411 
2412             pStockElxs[nStockId] = pRange;
2413         }
2414         break;
2415 
2416         case STOCKELX_DIGITAL_NOT:
2417         {
2418             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(0, 0));
2419 
2420             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2421 
2422             pStockElxs[nStockId] = pRange;
2423         }
2424         break;
2425 
2426         case STOCKELX_WORD_RIGHTLEFT:
2427         {
2428             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 1));
2429 
2430             pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
2431             pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
2432             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2433             pRange->m_chars.Push(RCHART('_'));
2434 
2435             pStockElxs[nStockId] = pRange;
2436         }
2437         break;
2438 
2439         case STOCKELX_WORD_RIGHTLEFT_NOT:
2440         {
2441             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 0));
2442 
2443             pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
2444             pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
2445             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2446             pRange->m_chars.Push(RCHART('_'));
2447 
2448             pStockElxs[nStockId] = pRange;
2449         }
2450         break;
2451 
2452         case STOCKELX_DOT_ALL_RIGHTLEFT:
2453             pStockElxs[nStockId] = Keep(new CRangeElxT <CHART>(1, 0));
2454             break;
2455 
2456         case STOCKELX_DOT_NOT_ALL_RIGHTLEFT:
2457         {
2458             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 0));
2459 
2460             pRange->m_chars.Push(RCHART('\n'));
2461 
2462             pStockElxs[nStockId] = pRange;
2463         }
2464         break;
2465 
2466         case STOCKELX_SPACE_RIGHTLEFT:
2467         {
2468             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 1));
2469 
2470             pRange->m_chars.Push(RCHART(' '));
2471             pRange->m_chars.Push(RCHART('\t'));
2472             pRange->m_chars.Push(RCHART('\r'));
2473             pRange->m_chars.Push(RCHART('\n'));
2474             pRange->m_chars.Push(RCHART('\f'));
2475             pRange->m_chars.Push(RCHART('\v'));
2476 
2477             pStockElxs[nStockId] = pRange;
2478         }
2479         break;
2480 
2481         case STOCKELX_SPACE_RIGHTLEFT_NOT:
2482         {
2483             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 0));
2484 
2485             pRange->m_chars.Push(RCHART(' '));
2486             pRange->m_chars.Push(RCHART('\t'));
2487             pRange->m_chars.Push(RCHART('\r'));
2488             pRange->m_chars.Push(RCHART('\n'));
2489             pRange->m_chars.Push(RCHART('\f'));
2490             pRange->m_chars.Push(RCHART('\v'));
2491 
2492             pStockElxs[nStockId] = pRange;
2493         }
2494         break;
2495 
2496         case STOCKELX_DIGITAL_RIGHTLEFT:
2497         {
2498             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 1));
2499 
2500             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2501 
2502             pStockElxs[nStockId] = pRange;
2503         }
2504         break;
2505 
2506         case STOCKELX_DIGITAL_RIGHTLEFT_NOT:
2507         {
2508             CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(1, 0));
2509 
2510             pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
2511 
2512             pStockElxs[nStockId] = pRange;
2513         }
2514         break;
2515         }
2516     }
2517 
2518     // return
2519     return pStockElxs[nStockId];
2520 }
2521 
2522 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildAlternative(int vaflags)
2523 {
2524     if (curr == CHART_INFO(0, 1))
2525         return GetStockElx(STOCKELX_EMPTY);
2526 
2527     // flag instance
2528     int flags = vaflags;
2529 
2530     // first part
2531     ElxInterface * pAlternativeOne = BuildList(flags);
2532 
2533     // check alternative
2534     if (curr == CHART_INFO(RCHART('|'), 1))
2535     {
2536         CAlternativeElx * pAlternative = (CAlternativeElx *)Keep(new CAlternativeElx());
2537         pAlternative->m_elxlist.Push(pAlternativeOne);
2538 
2539         // loop
2540         while (curr == CHART_INFO(RCHART('|'), 1))
2541         {
2542             // skip '|' itself
2543             MoveNext();
2544 
2545             pAlternativeOne = BuildList(flags);
2546             pAlternative->m_elxlist.Push(pAlternativeOne);
2547         }
2548 
2549         return pAlternative;
2550     }
2551 
2552     return pAlternativeOne;
2553 }
2554 
2555 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildList(int & flags)
2556 {
2557     if (curr == CHART_INFO(0, 1) || curr == CHART_INFO(RCHART('|'), 1) || curr == CHART_INFO(RCHART(')'), 1))
2558         return GetStockElx(STOCKELX_EMPTY);
2559 
2560     // first
2561     ElxInterface * pListOne = BuildRepeat(flags);
2562 
2563     if (curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1))
2564     {
2565         CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT));
2566         pList->m_elxlist.Push(pListOne);
2567 
2568         while (curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1))
2569         {
2570             pListOne = BuildRepeat(flags);
2571 
2572             // add
2573             pList->m_elxlist.Push(pListOne);
2574         }
2575 
2576         return pList;
2577     }
2578 
2579     return pListOne;
2580 }
2581 
2582 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildRepeat(int & flags)
2583 {
2584     // simple
2585     ElxInterface * pSimple = BuildSimple(flags);
2586 
2587     if (curr.type == 0) return pSimple;
2588 
2589     // is quantifier or not
2590     int bIsQuantifier = 1;
2591 
2592     // quantifier range
2593     unsigned int nMin = 0, nMax = 0;
2594 
2595     switch (curr.ch)
2596     {
2597     case RCHART('{'):
2598     {
2599         CBufferT <char> re;
2600 
2601         // skip '{'
2602         MoveNext();
2603 
2604         // copy
2605         while (curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('}'), 1))
2606         {
2607             re.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
2608             MoveNext();
2609         }
2610 
2611         // skip '}'
2612         MoveNext();
2613 
2614         // read
2615         int red;
2616         char * str = re.GetBuffer();
2617 
2618         if (!ReadDec(str, nMin))
2619             red = 0;
2620         else if (*str != ',')
2621             red = 1;
2622         else
2623         {
2624             str++;
2625 
2626             if (!ReadDec(str, nMax))
2627                 red = 2;
2628             else
2629                 red = 3;
2630         }
2631 
2632         // check
2633         if (red <= 1) nMax = nMin;
2634         if (red == 2) nMax = INT_MAX;
2635         if (nMax < nMin) nMax = nMin;
2636     }
2637     break;
2638 
2639     case RCHART('?'):
2640         nMin = 0;
2641         nMax = 1;
2642 
2643         // skip '?'
2644         MoveNext();
2645         break;
2646 
2647     case RCHART('*'):
2648         nMin = 0;
2649         nMax = INT_MAX;
2650 
2651         // skip '*'
2652         MoveNext();
2653         break;
2654 
2655     case RCHART('+'):
2656         nMin = 1;
2657         nMax = INT_MAX;
2658 
2659         // skip '+'
2660         MoveNext();
2661         break;
2662 
2663     default:
2664         bIsQuantifier = 0;
2665         break;
2666     }
2667 
2668     // do quantify
2669     if (bIsQuantifier)
2670     {
2671         // 0 times
2672         if (nMax == 0)
2673             return GetStockElx(STOCKELX_EMPTY);
2674 
2675         // fixed times
2676         if (nMin == nMax)
2677         {
2678             if (curr == CHART_INFO(RCHART('?'), 1) || curr == CHART_INFO(RCHART('+'), 1))
2679                 MoveNext();
2680 
2681             return Keep(new CRepeatElx(pSimple, nMin));
2682         }
2683 
2684         // range times
2685         if (curr == CHART_INFO(RCHART('?'), 1))
2686         {
2687             MoveNext();
2688             return Keep(new CReluctantElx(pSimple, nMin, nMax));
2689         }
2690         else if (curr == CHART_INFO(RCHART('+'), 1))
2691         {
2692             MoveNext();
2693             return Keep(new CPossessiveElx(pSimple, nMin, nMax));
2694         }
2695         else
2696         {
2697             return Keep(new CGreedyElx(pSimple, nMin, nMax));
2698         }
2699     }
2700 
2701     return pSimple;
2702 }
2703 
2704 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildSimple(int & flags)
2705 {
2706     CBufferT <CHART> fixed;
2707 
2708     while (curr != CHART_INFO(0, 1))
2709     {
2710         if (curr.type == 0)
2711         {
2712             if (next == CHART_INFO(RCHART('{'), 1) || next == CHART_INFO(RCHART('?'), 1) || next == CHART_INFO(RCHART('*'), 1) || next == CHART_INFO(RCHART('+'), 1))
2713             {
2714                 if (fixed.GetSize() == 0)
2715                 {
2716                     fixed.Append(curr.ch, 1);
2717                     MoveNext();
2718                 }
2719 
2720                 break;
2721             }
2722             else
2723             {
2724                 fixed.Append(curr.ch, 1);
2725                 MoveNext();
2726             }
2727         }
2728         else if (curr.type == 1)
2729         {
2730             CHART vch = curr.ch;
2731 
2732             // end of simple
2733             if (vch == RCHART(')') || vch == RCHART('|'))
2734                 break;
2735 
2736             // has fixed already
2737             if (fixed.GetSize() > 0)
2738                 break;
2739 
2740             // left parentheses
2741             if (vch == RCHART('('))
2742             {
2743                 return BuildRecursive(flags);
2744             }
2745 
2746             // char set
2747             if (vch == RCHART('[') || vch == RCHART('.') || vch == RCHART('w') || vch == RCHART('W') ||
2748                 vch == RCHART('s') || vch == RCHART('S') || vch == RCHART('d') || vch == RCHART('D')
2749                 )
2750             {
2751                 return BuildCharset(flags);
2752             }
2753 
2754             // boundary
2755             if (vch == RCHART('^') || vch == RCHART('$') || vch == RCHART('A') || vch == RCHART('Z') || vch == RCHART('z') ||
2756                 vch == RCHART('b') || vch == RCHART('B') || vch == RCHART('G') // vch == RCHART('<') || vch == RCHART('>')
2757                 )
2758             {
2759                 return BuildBoundary(flags);
2760             }
2761 
2762             // backref
2763             if (vch == RCHART('\\') || vch == RCHART('k') || vch == RCHART('g'))
2764             {
2765                 return BuildBackref(flags);
2766             }
2767 
2768             // treat vchar as char
2769             fixed.Append(curr.ch, 1);
2770             MoveNext();
2771         }
2772     }
2773 
2774     if (fixed.GetSize() > 0)
2775         return Keep(new CStringElxT <CHART>(fixed.GetBuffer(), fixed.GetSize(), flags & RIGHTTOLEFT, flags & IGNORECASE));
2776     else
2777         return GetStockElx(STOCKELX_EMPTY);
2778 }
2779 
2780 #define max(a, b)  (((a) > (b)) ? (a) : (b))
2781 #define min(a, b)  (((a) < (b)) ? (a) : (b))
2782 
2783 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildCharset(int & flags)
2784 {
2785     // char
2786     CHART ch = curr.ch;
2787 
2788     // skip
2789     MoveNext();
2790 
2791     switch (ch)
2792     {
2793     case RCHART('.'):
2794         return GetStockElx(
2795             flags & RIGHTTOLEFT ?
2796             ((flags & SINGLELINE) ? STOCKELX_DOT_ALL_RIGHTLEFT : STOCKELX_DOT_NOT_ALL_RIGHTLEFT) :
2797             ((flags & SINGLELINE) ? STOCKELX_DOT_ALL : STOCKELX_DOT_NOT_ALL)
2798         );
2799 
2800     case RCHART('w'):
2801         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT : STOCKELX_WORD);
2802 
2803     case RCHART('W'):
2804         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT_NOT : STOCKELX_WORD_NOT);
2805 
2806     case RCHART('s'):
2807         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT : STOCKELX_SPACE);
2808 
2809     case RCHART('S'):
2810         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT_NOT : STOCKELX_SPACE_NOT);
2811 
2812     case RCHART('d'):
2813         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT : STOCKELX_DIGITAL);
2814 
2815     case RCHART('D'):
2816         return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT_NOT : STOCKELX_DIGITAL_NOT);
2817 
2818     case RCHART('['):
2819     {
2820         CRangeElxT <CHART> * pRange;
2821 
2822         // create
2823         if (curr == CHART_INFO(RCHART(':'), 1))
2824         {
2825             // Backup before posix
2826             Snapshot shot;
2827             Backup(&shot);
2828 
2829             CBufferT <char> posix;
2830 
2831             do {
2832                 posix.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
2833                 MoveNext();
2834             } while (curr.ch != RCHART(0) && curr != CHART_INFO(RCHART(']'), 1));
2835 
2836             MoveNext(); // skip ']'
2837 
2838                         // posix
2839             CPosixElxT<CHART> * pposix = (CPosixElxT<CHART> *) Keep(new CPosixElxT <CHART>(posix.GetBuffer(), flags & RIGHTTOLEFT));
2840             if (pposix->m_posixfun != 0)
2841             {
2842                 return pposix;
2843             }
2844 
2845             // restore if not posix
2846             Restore(&shot);
2847         }
2848 
2849         if (curr == CHART_INFO(RCHART('^'), 1))
2850         {
2851             MoveNext(); // skip '^'
2852             pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(flags & RIGHTTOLEFT, 0));
2853         }
2854         else
2855         {
2856             pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART>(flags & RIGHTTOLEFT, 1));
2857         }
2858 
2859         // parse
2860         while (curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART(']'), 1))
2861         {
2862             ch = curr.ch;
2863 
2864             if (curr.type == 1 && (
2865                 ch == RCHART('.') || ch == RCHART('w') || ch == RCHART('W') || ch == RCHART('s') || ch == RCHART('S') || ch == RCHART('d') || ch == RCHART('D') ||
2866                 (ch == RCHART('[') && next == CHART_INFO(RCHART(':'), 1))
2867                 ))
2868             {
2869                 pRange->m_embeds.Push(BuildCharset(flags));
2870             }
2871             else if (next == CHART_INFO(RCHART('-'), 1) && nex2.type == 0)
2872             {
2873                 pRange->m_ranges.Push(ch); pRange->m_ranges.Push(nex2.ch);
2874 
2875                 // next
2876                 MoveNext();
2877                 MoveNext();
2878                 MoveNext();
2879             }
2880             else
2881             {
2882                 pRange->m_chars.Push(ch);
2883 
2884                 // next
2885                 MoveNext();
2886             }
2887         }
2888 
2889         // skip ']'
2890         MoveNext();
2891 
2892         if (flags & IGNORECASE)
2893         {
2894             CBufferT <CHART> & ranges = pRange->m_ranges;
2895             int i, oldcount = ranges.GetSize() / 2;
2896 
2897             for (i = 0; i < oldcount; i++)
2898             {
2899                 CHART newmin, newmax;
2900 
2901                 if (ranges[i * 2] <= RCHART('Z') && ranges[i * 2 + 1] >= RCHART('A'))
2902                 {
2903                     newmin = tolower(max(RCHART('A'), ranges[i * 2]));
2904                     newmax = tolower(min(RCHART('Z'), ranges[i * 2 + 1]));
2905 
2906                     if (newmin < ranges[i * 2] || newmax > ranges[i * 2 + 1])
2907                     {
2908                         ranges.Push(newmin);
2909                         ranges.Push(newmax);
2910                     }
2911                 }
2912 
2913                 if (ranges[i * 2] <= RCHART('z') && ranges[i * 2 + 1] >= RCHART('a'))
2914                 {
2915                     newmin = toupper(max(RCHART('a'), ranges[i * 2]));
2916                     newmax = toupper(min(RCHART('z'), ranges[i * 2 + 1]));
2917 
2918                     if (newmin < ranges[i * 2] || newmax > ranges[i * 2 + 1])
2919                     {
2920                         ranges.Push(newmin);
2921                         ranges.Push(newmax);
2922                     }
2923                 }
2924             }
2925 
2926             CBufferT <CHART> & chars = pRange->m_chars;
2927             oldcount = chars.GetSize();
2928             for (i = 0; i < oldcount; i++)
2929             {
2930                 if (isupper(chars[i]) && !pRange->IsContainChar(tolower(chars[i])))
2931                     chars.Push(tolower(chars[i]));
2932 
2933                 if (islower(chars[i]) && !pRange->IsContainChar(toupper(chars[i])))
2934                     chars.Push(toupper(chars[i]));
2935             }
2936         }
2937 
2938         return pRange;
2939     }
2940     }
2941 
2942     return GetStockElx(STOCKELX_EMPTY);
2943 }
2944 
2945 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildRecursive(int & flags)
2946 {
2947     // skip '('
2948     MoveNext();
2949 
2950     if (curr == CHART_INFO(RCHART('?'), 1))
2951     {
2952         ElxInterface * pElx = 0;
2953 
2954         // skip '?'
2955         MoveNext();
2956 
2957         int bNegative = 0;
2958         CHART named_end = RCHART('>');
2959 
2960         switch (curr.ch)
2961         {
2962         case RCHART('!'):
2963             bNegative = 1;
2964 
2965         case RCHART('='):
2966         {
2967             MoveNext(); // skip '!' or '='
2968             pElx = Keep(new CAssertElx(BuildAlternative(flags & ~RIGHTTOLEFT), !bNegative));
2969         }
2970         break;
2971 
2972         case RCHART('<'):
2973             switch (next.ch)
2974             {
2975             case RCHART('!'):
2976                 bNegative = 1;
2977 
2978             case RCHART('='):
2979                 MoveNext(); // skip '<'
2980                 MoveNext(); // skip '!' or '='
2981                 {
2982                     pElx = Keep(new CAssertElx(BuildAlternative(flags | RIGHTTOLEFT), !bNegative));
2983                 }
2984                 break;
2985 
2986             default: // named group
2987                 break;
2988             }
2989             // break if assertion // else named
2990             if (pElx != 0) break;
2991 
2992         case RCHART('P'):
2993             if (curr.ch == RCHART('P')) MoveNext(); // skip 'P'
2994 
2995         case RCHART('\''):
2996             if (curr.ch == RCHART('<')) named_end = RCHART('>');
2997             else if (curr.ch == RCHART('\'')) named_end = RCHART('\'');
2998             MoveNext(); // skip '<' or '\''
2999             {
3000                 // named number
3001                 int nThisBackref = m_nNextNamed++;
3002 
3003                 CListElx    * pList = (CListElx    *)Keep(new CListElx(flags & RIGHTTOLEFT));
3004                 CBracketElx * pleft = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 1 : 0));
3005                 CBracketElx * pright = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 0 : 1));
3006 
3007                 // save name
3008                 CBufferT <CHART> & name = pleft->m_szNamed;
3009                 CBufferT <char> num;
3010 
3011                 while (curr.ch != RCHART(0) && curr.ch != named_end)
3012                 {
3013                     name.Append(curr.ch, 1);
3014                     num.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
3015                     MoveNext();
3016                 }
3017                 MoveNext(); // skip '>' or '\''
3018 
3019                             // check <num>
3020                 unsigned int number;
3021                 char * str = num.GetBuffer();
3022 
3023                 if (ReadDec(str, number) ? (*str == '\0') : 0)
3024                 {
3025                     pleft->m_nnumber = number;
3026                     pright->m_nnumber = number;
3027 
3028                     name.Release();
3029                 }
3030 
3031                 // left, center, right
3032                 pList->m_elxlist.Push(pleft);
3033                 pList->m_elxlist.Push(BuildAlternative(flags));
3034                 pList->m_elxlist.Push(pright);
3035 
3036                 // for recursive
3037                 m_namedlist.Prepare(nThisBackref);
3038                 m_namedlist[nThisBackref] = pList;
3039 
3040                 pElx = pList;
3041             }
3042             break;
3043 
3044         case RCHART('>'):
3045         {
3046             MoveNext(); // skip '>'
3047             pElx = Keep(new CIndependentElx(BuildAlternative(flags)));
3048         }
3049         break;
3050 
3051         case RCHART('R'):
3052             MoveNext(); // skip 'R'
3053             while (curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space
3054 
3055             if (curr.ch == RCHART('<') || curr.ch == RCHART('\''))
3056             {
3057                 named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('\'');
3058                 CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(-3));
3059 
3060                 MoveNext(); // skip '<' or '\\'
3061 
3062                             // save name
3063                 CBufferT <CHART> & name = pDelegate->m_szNamed;
3064                 CBufferT <char> num;
3065 
3066                 while (curr.ch != RCHART(0) && curr.ch != named_end)
3067                 {
3068                     name.Append(curr.ch, 1);
3069                     num.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
3070                     MoveNext();
3071                 }
3072                 MoveNext(); // skip '>' or '\''
3073 
3074                             // check <num>
3075                 unsigned int number;
3076                 char * str = num.GetBuffer();
3077 
3078                 if (ReadDec(str, number) ? (*str == '\0') : 0)
3079                 {
3080                     pDelegate->m_ndata = number;
3081                     name.Release();
3082                 }
3083 
3084                 m_recursivelist.Push(pDelegate);
3085                 pElx = pDelegate;
3086             }
3087             else
3088             {
3089                 CBufferT <char> rto;
3090                 while (curr.ch != RCHART(0) && curr.ch != RCHART(')'))
3091                 {
3092                     rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
3093                     MoveNext();
3094                 }
3095 
3096                 unsigned int rtono = 0;
3097                 char * str = rto.GetBuffer();
3098                 ReadDec(str, rtono);
3099 
3100                 CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono));
3101 
3102                 m_recursivelist.Push(pDelegate);
3103                 pElx = pDelegate;
3104             }
3105             break;
3106 
3107         case RCHART('('):
3108         {
3109             CConditionElx * pConditionElx = (CConditionElx *)Keep(new CConditionElx());
3110 
3111             // condition
3112             ElxInterface * & pCondition = pConditionElx->m_pelxask;
3113 
3114             if (next == CHART_INFO(RCHART('?'), 1))
3115             {
3116                 pCondition = BuildRecursive(flags);
3117             }
3118             else // named, assert or number
3119             {
3120                 MoveNext(); // skip '('
3121                 int pos0 = curr.pos;
3122 
3123                 // save elx condition
3124                 pCondition = Keep(new CAssertElx(BuildAlternative(flags), 1));
3125 
3126                 // save name
3127                 pConditionElx->m_szNamed.Append(m_pattern.GetBuffer() + pos0, curr.pos - pos0, 1);
3128 
3129                 // save number
3130                 CBufferT <char> numstr;
3131                 while (pos0 < curr.pos)
3132                 {
3133                     CHART ch = m_pattern[pos0];
3134                     numstr.Append(((ch & (CHART)0xff) == ch) ? (char)ch : 0, 1);
3135                     pos0++;
3136                 }
3137 
3138                 unsigned int number;
3139                 char * str = numstr.GetBuffer();
3140 
3141                 // valid group number
3142                 if (ReadDec(str, number) ? (*str == '\0') : 0)
3143                 {
3144                     pConditionElx->m_nnumber = number;
3145                     pCondition = 0;
3146                 }
3147                 else // maybe elx, maybe named
3148                 {
3149                     pConditionElx->m_nnumber = -1;
3150                     m_namedconditionlist.Push(pConditionElx);
3151                 }
3152 
3153                 MoveNext(); // skip ')'
3154             }
3155 
3156             // alternative
3157             {
3158                 int newflags = flags;
3159 
3160                 pConditionElx->m_pelxyes = BuildList(newflags);
3161             }
3162 
3163             if (curr.ch == RCHART('|'))
3164             {
3165                 MoveNext(); // skip '|'
3166 
3167                 pConditionElx->m_pelxno = BuildAlternative(flags);
3168             }
3169             else
3170             {
3171                 pConditionElx->m_pelxno = 0;
3172             }
3173 
3174             pElx = pConditionElx;
3175         }
3176         break;
3177 
3178         default:
3179             while (curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space
3180 
3181             if (curr.ch >= RCHART('0') && curr.ch <= RCHART('9')) // recursive (?1) => (?R1)
3182             {
3183                 CBufferT <char> rto;
3184                 while (curr.ch != RCHART(0) && curr.ch != RCHART(')'))
3185                 {
3186                     rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
3187                     MoveNext();
3188                 }
3189 
3190                 unsigned int rtono = 0;
3191                 char * str = rto.GetBuffer();
3192                 ReadDec(str, rtono);
3193 
3194                 CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono));
3195 
3196                 m_recursivelist.Push(pDelegate);
3197                 pElx = pDelegate;
3198             }
3199             else
3200             {
3201                 // flag
3202                 int newflags = flags;
3203                 while (curr != CHART_INFO(0, 1) && curr.ch != RCHART(':') && curr.ch != RCHART(')') && curr != CHART_INFO(RCHART('('), 1))
3204                 {
3205                     int tochange = 0;
3206 
3207                     switch (curr.ch)
3208                     {
3209                     case RCHART('i'):
3210                     case RCHART('I'):
3211                         tochange = IGNORECASE;
3212                         break;
3213 
3214                     case RCHART('s'):
3215                     case RCHART('S'):
3216                         tochange = SINGLELINE;
3217                         break;
3218 
3219                     case RCHART('m'):
3220                     case RCHART('M'):
3221                         tochange = MULTILINE;
3222                         break;
3223 
3224                     case RCHART('g'):
3225                     case RCHART('G'):
3226                         tochange = GLOBAL;
3227                         break;
3228 
3229                     case RCHART('-'):
3230                         bNegative = 1;
3231                         break;
3232                     }
3233 
3234                     if (bNegative)
3235                         newflags &= ~tochange;
3236                     else
3237                         newflags |= tochange;
3238 
3239                     // move to next char
3240                     MoveNext();
3241                 }
3242 
3243                 if (curr.ch == RCHART(':') || curr == CHART_INFO(RCHART('('), 1))
3244                 {
3245                     // skip ':'
3246                     if (curr.ch == RCHART(':')) MoveNext();
3247 
3248                     pElx = BuildAlternative(newflags);
3249                 }
3250                 else
3251                 {
3252                     // change parent flags
3253                     flags = newflags;
3254 
3255                     pElx = GetStockElx(STOCKELX_EMPTY);
3256                 }
3257             }
3258             break;
3259         }
3260 
3261         MoveNext(); // skip ')'
3262 
3263         return pElx;
3264     }
3265     else
3266     {
3267         // group and number
3268         CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT));
3269         int nThisBackref = ++m_nMaxNumber;
3270 
3271         // left, center, right
3272         pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 1 : 0)));
3273         pList->m_elxlist.Push(BuildAlternative(flags));
3274         pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 0 : 1)));
3275 
3276         // for recursive
3277         m_grouplist.Prepare(nThisBackref);
3278         m_grouplist[nThisBackref] = pList;
3279 
3280         // right
3281         MoveNext(); // skip ')' 
3282 
3283         return pList;
3284     }
3285 }
3286 
3287 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildBoundary(int & flags)
3288 {
3289     // char
3290     CHART ch = curr.ch;
3291 
3292     // skip
3293     MoveNext();
3294 
3295     switch (ch)
3296     {
3297     case RCHART('^'):
3298         return Keep(new CBoundaryElxT <CHART>((flags & MULTILINE) ? BOUNDARY_LINE_BEGIN : BOUNDARY_FILE_BEGIN));
3299 
3300     case RCHART('$'):
3301         return Keep(new CBoundaryElxT <CHART>((flags & MULTILINE) ? BOUNDARY_LINE_END : BOUNDARY_FILE_END));
3302 
3303     case RCHART('b'):
3304         return Keep(new CBoundaryElxT <CHART>(BOUNDARY_WORD_EDGE));
3305 
3306     case RCHART('B'):
3307         return Keep(new CBoundaryElxT <CHART>(BOUNDARY_WORD_EDGE, 0));
3308 
3309     case RCHART('A'):
3310         return Keep(new CBoundaryElxT <CHART>(BOUNDARY_FILE_BEGIN));
3311 
3312     case RCHART('Z'):
3313         return Keep(new CBoundaryElxT <CHART>(BOUNDARY_FILE_END_N));
3314 
3315     case RCHART('z'):
3316         return Keep(new CBoundaryElxT <CHART>(BOUNDARY_FILE_END));
3317 
3318     case RCHART('G'):
3319         if (flags & GLOBAL)
3320             return Keep(new CGlobalElx());
3321         else
3322             return GetStockElx(STOCKELX_EMPTY);
3323 
3324     default:
3325         return GetStockElx(STOCKELX_EMPTY);
3326     }
3327 }
3328 
3329 template <class CHART> ElxInterface * CBuilderT <CHART> ::BuildBackref(int & flags)
3330 {
3331     // skip '\\' or '\k' or '\g'
3332     MoveNext();
3333 
3334     if (curr.ch == RCHART('<') || curr.ch == RCHART('\''))
3335     {
3336         CHART named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('\'');
3337         CBackrefElxT <CHART> * pbackref = (CBackrefElxT <CHART> *)Keep(new CBackrefElxT <CHART>(-1, flags & RIGHTTOLEFT, flags & IGNORECASE));
3338 
3339         MoveNext(); // skip '<' or '\''
3340 
3341                     // save name
3342         CBufferT <CHART> & name = pbackref->m_szNamed;
3343         CBufferT <char> num;
3344 
3345         while (curr.ch != RCHART(0) && curr.ch != named_end)
3346         {
3347             name.Append(curr.ch, 1);
3348             num.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
3349             MoveNext();
3350         }
3351         MoveNext(); // skip '>' or '\''
3352 
3353                     // check <num>
3354         unsigned int number;
3355         char * str = num.GetBuffer();
3356 
3357         if (ReadDec(str, number) ? (*str == '\0') : 0)
3358         {
3359             pbackref->m_nnumber = number;
3360             name.Release();
3361         }
3362         else
3363         {
3364             m_namedbackreflist.Push(pbackref);
3365         }
3366 
3367         return pbackref;
3368     }
3369     else
3370     {
3371         unsigned int nbackref = 0;
3372 
3373         for (int i = 0; i < 3; i++)
3374         {
3375             if (curr.ch >= RCHART('0') && curr.ch <= RCHART('9'))
3376                 nbackref = nbackref * 10 + (curr.ch - RCHART('0'));
3377             else
3378                 break;
3379 
3380             MoveNext();
3381         }
3382 
3383         return Keep(new CBackrefElxT <CHART>(nbackref, flags & RIGHTTOLEFT, flags & IGNORECASE));
3384     }
3385 }
3386 
3387 template <class CHART> int CBuilderT <CHART> ::ReadDec(char * & str, unsigned int & dec)
3388 {
3389     int s = 0;
3390     while (str[s] != 0 && isspace(str[s])) s++;
3391 
3392     if (str[s] < '0' || str[s] > '9') return 0;
3393 
3394     dec = 0;
3395     unsigned int i;
3396 
3397     for (i = s; i < sizeof(CHART) * 3 + s; i++)
3398     {
3399         if (str[i] >= '0' && str[i] <= '9')
3400             dec = dec * 10 + (str[i] - '0');
3401         else
3402             break;
3403     }
3404 
3405     while (str[i] != 0 && isspace(str[i])) i++;
3406     str += i;
3407 
3408     return 1;
3409 }
3410 
3411 //
3412 // Regexp
3413 //
3414 template <class CHART> class CRegexpT
3415 {
3416 public:
3417     CRegexpT(const CHART * pattern = 0, int flags = 0);
3418     CRegexpT(const CHART * pattern, int length, int flags);
3419     void Compile(const CHART * pattern, int flags = 0);
3420     void Compile(const CHART * pattern, int length, int flags);
3421 
3422 public:
3423     MatchResult MatchExact(const CHART * tstring, CContext * pContext = 0) const;
3424     MatchResult MatchExact(const CHART * tstring, int length, CContext * pContext = 0) const;
3425     MatchResult Match(const CHART * tstring, int start = -1, CContext * pContext = 0) const;
3426     MatchResult Match(const CHART * tstring, int length, int start, CContext * pContext = 0) const;
3427     MatchResult Match(CContext * pContext) const;
3428     CContext * PrepareMatch(const CHART * tstring, int start = -1, CContext * pContext = 0) const;
3429     CContext * PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext = 0) const;
3430     CHART * Replace(const CHART * tstring, const CHART * replaceto, int start = -1, int ntimes = -1, MatchResult * result = 0, CContext * pContext = 0) const;
3431     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;
3432     int GetNamedGroupNumber(const CHART * group_name) const;
3433 
3434 public:
3435     static void ReleaseString(CHART    * tstring);
3436     static void ReleaseContext(CContext * pContext);
3437 
3438 public:
3439     CBuilderT <CHART> m_builder;
3440 };
3441 
3442 //
3443 // Implementation
3444 //
3445 template <class CHART> CRegexpT <CHART> ::CRegexpT(const CHART * pattern, int flags)
3446 {
3447     Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
3448 }
3449 
3450 template <class CHART> CRegexpT <CHART> ::CRegexpT(const CHART * pattern, int length, int flags)
3451 {
3452     Compile(pattern, length, flags);
3453 }
3454 
3455 template <class CHART> inline void CRegexpT <CHART> ::Compile(const CHART * pattern, int flags)
3456 {
3457     Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
3458 }
3459 
3460 template <class CHART> void CRegexpT <CHART> ::Compile(const CHART * pattern, int length, int flags)
3461 {
3462     m_builder.Clear();
3463     if (pattern != 0) m_builder.Build(CBufferRefT<CHART>(pattern, length), flags);
3464 }
3465 
3466 template <class CHART> inline MatchResult CRegexpT <CHART> ::MatchExact(const CHART * tstring, CContext * pContext) const
3467 {
3468     return MatchExact(tstring, CBufferRefT<CHART>(tstring).GetSize(), pContext);
3469 }
3470 
3471 template <class CHART> MatchResult CRegexpT <CHART> ::MatchExact(const CHART * tstring, int length, CContext * pContext) const
3472 {
3473     if (m_builder.m_pTopElx == 0)
3474         return 0;
3475 
3476     // info
3477     int endpos = 0;
3478 
3479     CContext context;
3480     if (pContext == 0) pContext = &context;
3481 
3482     pContext->m_stack.Restore(0);
3483     pContext->m_capturestack.Restore(0);
3484     pContext->m_captureindex.Restore(0);
3485 
3486     pContext->m_nParenZindex = 0;
3487     pContext->m_nLastBeginPos = -1;
3488     pContext->m_pMatchString = (void*)tstring;
3489     pContext->m_pMatchStringLength = length;
3490     pContext->m_nCursiveLimit = 100;
3491 
3492     if (m_builder.m_nFlags & RIGHTTOLEFT)
3493     {
3494         pContext->m_nBeginPos = length;
3495         pContext->m_nCurrentPos = length;
3496         endpos = 0;
3497     }
3498     else
3499     {
3500         pContext->m_nBeginPos = 0;
3501         pContext->m_nCurrentPos = 0;
3502         endpos = length;
3503     }
3504 
3505     pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1);
3506     pContext->m_captureindex[0] = 0;
3507     pContext->m_capturestack.Push(0);
3508     pContext->m_capturestack.Push(pContext->m_nCurrentPos);
3509     pContext->m_capturestack.Push(-1);
3510     pContext->m_capturestack.Push(-1);
3511 
3512     // match
3513     if (!m_builder.m_pTopElx->Match(pContext))
3514         return 0;
3515     else
3516     {
3517         while (pContext->m_nCurrentPos != endpos)
3518         {
3519             if (!m_builder.m_pTopElx->MatchNext(pContext))
3520                 return 0;
3521             else
3522             {
3523                 if (pContext->m_nLastBeginPos == pContext->m_nBeginPos && pContext->m_nBeginPos == pContext->m_nCurrentPos)
3524                     return 0;
3525                 else
3526                     pContext->m_nLastBeginPos = pContext->m_nCurrentPos;
3527             }
3528         }
3529 
3530         // end pos
3531         pContext->m_capturestack[2] = pContext->m_nCurrentPos;
3532 
3533         return MatchResult(pContext, m_builder.m_nMaxNumber);
3534     }
3535 }
3536 
3537 template <class CHART> MatchResult CRegexpT <CHART> ::Match(const CHART * tstring, int start, CContext * pContext) const
3538 {
3539     return Match(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
3540 }
3541 
3542 template <class CHART> MatchResult CRegexpT <CHART> ::Match(const CHART * tstring, int length, int start, CContext * pContext) const
3543 {
3544     if (m_builder.m_pTopElx == 0)
3545         return 0;
3546 
3547     CContext context;
3548     if (pContext == 0) pContext = &context;
3549 
3550     PrepareMatch(tstring, length, start, pContext);
3551 
3552     return Match(pContext);
3553 }
3554 
3555 template <class CHART> MatchResult CRegexpT <CHART> ::Match(CContext * pContext) const
3556 {
3557     if (m_builder.m_pTopElx == 0)
3558         return 0;
3559 
3560     int endpos, delta;
3561 
3562     if (m_builder.m_nFlags & RIGHTTOLEFT)
3563     {
3564         endpos = -1;
3565         delta = -1;
3566     }
3567     else
3568     {
3569         endpos = pContext->m_pMatchStringLength + 1;
3570         delta = 1;
3571     }
3572 
3573     while (pContext->m_nCurrentPos != endpos)
3574     {
3575         pContext->m_captureindex.Restore(0);
3576         pContext->m_stack.Restore(0);
3577         pContext->m_capturestack.Restore(0);
3578 
3579         pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1);
3580         pContext->m_captureindex[0] = 0;
3581         pContext->m_capturestack.Push(0);
3582         pContext->m_capturestack.Push(pContext->m_nCurrentPos);
3583         pContext->m_capturestack.Push(-1);
3584         pContext->m_capturestack.Push(-1);
3585 
3586         if (m_builder.m_pTopElx->Match(pContext))
3587         {
3588             pContext->m_capturestack[2] = pContext->m_nCurrentPos;
3589 
3590             // zero width
3591             if (pContext->m_capturestack[1] == pContext->m_nCurrentPos)
3592             {
3593                 pContext->m_nCurrentPos += delta;
3594             }
3595 
3596             // save pos
3597             pContext->m_nLastBeginPos = pContext->m_nBeginPos;
3598             pContext->m_nBeginPos = pContext->m_nCurrentPos;
3599 
3600             // return
3601             return MatchResult(pContext, m_builder.m_nMaxNumber);
3602         }
3603         else
3604         {
3605             pContext->m_nCurrentPos += delta;
3606         }
3607     }
3608 
3609     return 0;
3610 }
3611 
3612 template <class CHART> inline CContext * CRegexpT <CHART> ::PrepareMatch(const CHART * tstring, int start, CContext * pContext) const
3613 {
3614     return PrepareMatch(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
3615 }
3616 
3617 template <class CHART> CContext * CRegexpT <CHART> ::PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext) const
3618 {
3619     if (m_builder.m_pTopElx == 0)
3620         return 0;
3621 
3622     if (pContext == 0) pContext = new CContext();
3623 
3624     pContext->m_nParenZindex = 0;
3625     pContext->m_nLastBeginPos = -1;
3626     pContext->m_pMatchString = (void*)tstring;
3627     pContext->m_pMatchStringLength = length;
3628     pContext->m_nCursiveLimit = 100;
3629 
3630     if (start < 0)
3631     {
3632         if (m_builder.m_nFlags & RIGHTTOLEFT)
3633         {
3634             pContext->m_nBeginPos = length;
3635             pContext->m_nCurrentPos = length;
3636         }
3637         else
3638         {
3639             pContext->m_nBeginPos = 0;
3640             pContext->m_nCurrentPos = 0;
3641         }
3642     }
3643     else
3644     {
3645         if (start > length) start = length + ((m_builder.m_nFlags & RIGHTTOLEFT) ? 0 : 1);
3646 
3647         pContext->m_nBeginPos = start;
3648         pContext->m_nCurrentPos = start;
3649     }
3650 
3651     return pContext;
3652 }
3653 
3654 template <class CHART> inline int CRegexpT <CHART> ::GetNamedGroupNumber(const CHART * group_name) const
3655 {
3656     return m_builder.GetNamedNumber(group_name);
3657 }
3658 
3659 template <class CHART> CHART * CRegexpT <CHART> ::Replace(const CHART * tstring, const CHART * replaceto, int start, int ntimes, MatchResult * result, CContext * pContext) const
3660 {
3661     int result_length = 0;
3662     return Replace(tstring, CBufferRefT<CHART>(tstring).GetSize(), replaceto, CBufferRefT<CHART>(replaceto).GetSize(), result_length, start, ntimes, result, pContext);
3663 }
3664 
3665 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
3666 {
3667     if (m_builder.m_pTopElx == 0) return 0;
3668 
3669     // --- compile replace to ---
3670 
3671     CBufferT <int> compiledto;
3672 
3673     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') };
3674     static CRegexpT <CHART> rtoreg(rtoptn);
3675 
3676     MatchResult local_result(0), *result = remote_result ? remote_result : &local_result;
3677 
3678     // prepare
3679     CContext * pContext = rtoreg.PrepareMatch(replaceto, to_length, -1, oContext);
3680     int lastIndex = 0, nmatch = 0;
3681 
3682     while (((*result) = rtoreg.Match(pContext)).IsMatched())
3683     {
3684         int delta = result->GetStart() - lastIndex;
3685         if (delta > 0)
3686         {
3687             compiledto.Push(lastIndex);
3688             compiledto.Push(delta);
3689         }
3690 
3691         lastIndex = result->GetStart();
3692         delta = 2;
3693 
3694         switch (replaceto[lastIndex + 1])
3695         {
3696         case RCHART('$'):
3697             compiledto.Push(lastIndex);
3698             compiledto.Push(1);
3699             break;
3700 
3701         case RCHART('&'):
3702         case RCHART('`'):
3703         case RCHART('\''):
3704         case RCHART('+'):
3705         case RCHART('_'):
3706             compiledto.Push(-1);
3707             compiledto.Push((int)replaceto[lastIndex + 1]);
3708             break;
3709 
3710         case RCHART('{'):
3711             delta = result->GetEnd() - result->GetStart();
3712             nmatch = m_builder.GetNamedNumber(CBufferRefT <CHART>(replaceto + (lastIndex + 2), delta - 3));
3713 
3714             if (nmatch > 0 && nmatch <= m_builder.m_nMaxNumber)
3715             {
3716                 compiledto.Push(-2);
3717                 compiledto.Push(nmatch);
3718             }
3719             else
3720             {
3721                 compiledto.Push(lastIndex);
3722                 compiledto.Push(delta);
3723             }
3724             break;
3725 
3726         default:
3727             nmatch = 0;
3728             for (delta = 1; delta <= 3; delta++)
3729             {
3730                 CHART ch = replaceto[lastIndex + delta];
3731 
3732                 if (ch < RCHART('0') || ch > RCHART('9'))
3733                     break;
3734 
3735                 nmatch = nmatch * 10 + (ch - RCHART('0'));
3736             }
3737 
3738             if (nmatch > m_builder.m_nMaxNumber)
3739             {
3740                 while (nmatch > m_builder.m_nMaxNumber)
3741                 {
3742                     nmatch /= 10;
3743                     delta--;
3744                 }
3745 
3746                 if (nmatch == 0)
3747                 {
3748                     delta = 1;
3749                 }
3750             }
3751 
3752             if (delta == 1)
3753             {
3754                 compiledto.Push(lastIndex);
3755                 compiledto.Push(1);
3756             }
3757             else
3758             {
3759                 compiledto.Push(-2);
3760                 compiledto.Push(nmatch);
3761             }
3762             break;
3763         }
3764 
3765         lastIndex += delta;
3766     }
3767 
3768     if (lastIndex < to_length)
3769     {
3770         compiledto.Push(lastIndex);
3771         compiledto.Push(to_length - lastIndex);
3772     }
3773 
3774     int rightleft = m_builder.m_nFlags & RIGHTTOLEFT;
3775 
3776     int tb = rightleft ? compiledto.GetSize() - 2 : 0;
3777     int te = rightleft ? -2 : compiledto.GetSize();
3778     int ts = rightleft ? -2 : 2;
3779 
3780     // --- compile complete ---
3781 
3782     int beginpos = rightleft ? string_length : 0;
3783     int endpos = rightleft ? 0 : string_length;
3784 
3785     int toIndex0 = 0;
3786     int toIndex1 = 0;
3787     int i, ntime;
3788 
3789     CBufferT <const CHART *> buffer;
3790 
3791     // prepare
3792     pContext = PrepareMatch(tstring, string_length, start, pContext);
3793     lastIndex = beginpos;
3794 
3795     // Match
3796     for (ntime = 0; ntimes < 0 || ntime < ntimes; ntime++)
3797     {
3798         (*result) = Match(pContext);
3799 
3800         if (!result->IsMatched())
3801             break;
3802 
3803         // before
3804         if (rightleft)
3805         {
3806             int distance = lastIndex - result->GetEnd();
3807             if (distance)
3808             {
3809                 buffer.Push(tstring + result->GetEnd());
3810                 buffer.Push((const CHART *)distance);
3811 
3812                 toIndex1 -= distance;
3813             }
3814             lastIndex = result->GetStart();
3815         }
3816         else
3817         {
3818             int distance = result->GetStart() - lastIndex;
3819             if (distance)
3820             {
3821                 buffer.Push(tstring + lastIndex);
3822                 buffer.Push((const CHART *)distance);
3823 
3824                 toIndex1 += distance;
3825             }
3826             lastIndex = result->GetEnd();
3827         }
3828 
3829         toIndex0 = toIndex1;
3830 
3831         // middle
3832         for (i = tb; i != te; i += ts)
3833         {
3834             int off = compiledto[i];
3835             int len = compiledto[i + 1];
3836 
3837             const CHART * sub = replaceto + off;
3838 
3839             if (off == -1)
3840             {
3841                 switch (RCHART(len))
3842                 {
3843                 case RCHART('&'):
3844                     sub = tstring + result->GetStart();
3845                     len = result->GetEnd() - result->GetStart();
3846                     break;
3847 
3848                 case RCHART('`'):
3849                     sub = tstring;
3850                     len = result->GetStart();
3851                     break;
3852 
3853                 case RCHART('\''):
3854                     sub = tstring + result->GetEnd();
3855                     len = string_length - result->GetEnd();
3856                     break;
3857 
3858                 case RCHART('+'):
3859                     for (nmatch = result->MaxGroupNumber(); nmatch >= 0; nmatch--)
3860                     {
3861                         if (result->GetGroupStart(nmatch) >= 0) break;
3862                     }
3863                     sub = tstring + result->GetGroupStart(nmatch);
3864                     len = result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch);
3865                     break;
3866 
3867                 case RCHART('_'):
3868                     sub = tstring;
3869                     len = string_length;
3870                     break;
3871                 }
3872             }
3873             else if (off == -2)
3874             {
3875                 sub = tstring + result->GetGroupStart(len);
3876                 len = result->GetGroupEnd(len) - result->GetGroupStart(len);
3877             }
3878 
3879             buffer.Push(sub);
3880             buffer.Push((const CHART *)len);
3881 
3882             toIndex1 += rightleft ? (-len) : len;
3883         }
3884     }
3885 
3886     // after
3887     if (rightleft)
3888     {
3889         if (endpos < lastIndex)
3890         {
3891             buffer.Push(tstring + endpos);
3892             buffer.Push((const CHART *)(lastIndex - endpos));
3893         }
3894     }
3895     else
3896     {
3897         if (lastIndex < endpos)
3898         {
3899             buffer.Push(tstring + lastIndex);
3900             buffer.Push((const CHART *)(endpos - lastIndex));
3901         }
3902     }
3903 
3904     if (oContext == 0) ReleaseContext(pContext);
3905 
3906     // join string
3907     result_length = 0;
3908     for (i = 0; i < buffer.GetSize(); i += 2)
3909     {
3910         result_length += (int)buffer[i + 1];
3911     }
3912 
3913     CBufferT <CHART> result_string;
3914     result_string.Prepare(result_length);
3915     result_string.Restore(0);
3916 
3917     if (rightleft)
3918     {
3919         for (i = buffer.GetSize() - 2; i >= 0; i -= 2)
3920         {
3921             result_string.Append(buffer[i], (int)buffer[i + 1]);
3922         }
3923     }
3924     else
3925     {
3926         for (i = 0; i < buffer.GetSize(); i += 2)
3927         {
3928             result_string.Append(buffer[i], (int)buffer[i + 1]);
3929         }
3930     }
3931 
3932     result_string.Append(0);
3933 
3934     result->m_result.Append(result_length, 3);
3935     result->m_result.Append(ntime);
3936 
3937     if (rightleft)
3938     {
3939         result->m_result.Append(result_length - toIndex1);
3940         result->m_result.Append(result_length - toIndex0);
3941     }
3942     else
3943     {
3944         result->m_result.Append(toIndex0);
3945         result->m_result.Append(toIndex1);
3946     }
3947 
3948     return result_string.Detach();
3949 }
3950 
3951 template <class CHART> inline void CRegexpT <CHART> ::ReleaseString(CHART * tstring)
3952 {
3953     if (tstring != 0) free(tstring);
3954 }
3955 
3956 template <class CHART> inline void CRegexpT <CHART> ::ReleaseContext(CContext * pContext)
3957 {
3958     if (pContext != 0) delete pContext;
3959 }
3960 
3961 //
3962 // All implementations
3963 //
3964 template <int x> CAlternativeElxT <x> ::CAlternativeElxT()
3965 {
3966 }
3967 
3968 template <int x> int CAlternativeElxT <x> ::Match(CContext * pContext) const
3969 {
3970     if (m_elxlist.GetSize() == 0)
3971         return 1;
3972 
3973     // try all
3974     for (int n = 0; n < m_elxlist.GetSize(); n++)
3975     {
3976         if (m_elxlist[n]->Match(pContext))
3977         {
3978             pContext->m_stack.Push(n);
3979             return 1;
3980         }
3981     }
3982 
3983     return 0;
3984 }
3985 
3986 template <int x> int CAlternativeElxT <x> ::MatchNext(CContext * pContext) const
3987 {
3988     if (m_elxlist.GetSize() == 0)
3989         return 0;
3990 
3991     int n = 0;
3992 
3993     // recall prev
3994     pContext->m_stack.Pop(n);
3995 
3996     // prev
3997     if (m_elxlist[n]->MatchNext(pContext))
3998     {
3999         pContext->m_stack.Push(n);
4000         return 1;
4001     }
4002     else
4003     {
4004         // try rest
4005         for (n++; n < m_elxlist.GetSize(); n++)
4006         {
4007             if (m_elxlist[n]->Match(pContext))
4008             {
4009                 pContext->m_stack.Push(n);
4010                 return 1;
4011             }
4012         }
4013 
4014         return 0;
4015     }
4016 }
4017 
4018 // assertx.cpp: implementation of the CAssertElx class.
4019 //
4020 template <int x> CAssertElxT <x> ::CAssertElxT(ElxInterface * pelx, int byes)
4021 {
4022     m_pelx = pelx;
4023     m_byes = byes;
4024 }
4025 
4026 template <int x> int CAssertElxT <x> ::Match(CContext * pContext) const
4027 {
4028     int nbegin = pContext->m_nCurrentPos;
4029     int nsize = pContext->m_stack.GetSize();
4030     int ncsize = pContext->m_capturestack.GetSize();
4031     int bsucc;
4032 
4033     // match
4034     if (m_byes)
4035         bsucc = m_pelx->Match(pContext);
4036     else
4037         bsucc = !m_pelx->Match(pContext);
4038 
4039     // status
4040     pContext->m_stack.Restore(nsize);
4041     pContext->m_nCurrentPos = nbegin;
4042 
4043     if (bsucc)
4044         pContext->m_stack.Push(ncsize);
4045     else
4046         pContext->m_capturestack.Restore(ncsize);
4047 
4048     return bsucc;
4049 }
4050 
4051 template <int x> int CAssertElxT <x> ::MatchNext(CContext * pContext) const
4052 {
4053     int ncsize = 0;
4054 
4055     pContext->m_stack.Pop(ncsize);
4056     pContext->m_capturestack.Restore(ncsize);
4057 
4058     return 0;
4059 }
4060 
4061 // emptyelx.cpp: implementation of the CEmptyElx class.
4062 //
4063 template <int x> CEmptyElxT <x> ::CEmptyElxT()
4064 {
4065 }
4066 
4067 template <int x> int CEmptyElxT <x> ::Match(CContext *) const
4068 {
4069     return 1;
4070 }
4071 
4072 template <int x> int CEmptyElxT <x> ::MatchNext(CContext *) const
4073 {
4074     return 0;
4075 }
4076 
4077 // globalx.cpp: implementation of the CGlobalElx class.
4078 //
4079 template <int x> CGlobalElxT <x> ::CGlobalElxT()
4080 {
4081 }
4082 
4083 template <int x> int CGlobalElxT <x> ::Match(CContext * pContext) const
4084 {
4085     return pContext->m_nCurrentPos == pContext->m_nBeginPos;
4086 }
4087 
4088 template <int x> int CGlobalElxT <x> ::MatchNext(CContext *) const
4089 {
4090     return 0;
4091 }
4092 
4093 // greedelx.cpp: implementation of the CGreedyElx class.
4094 //
4095 template <int x> CGreedyElxT <x> ::CGreedyElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x>(pelx, nmin)
4096 {
4097     m_nvart = nmax - nmin;
4098 }
4099 
4100 template <int x> int CGreedyElxT <x> ::Match(CContext * pContext) const
4101 {
4102     if (!CRepeatElxT <x> ::MatchFixed(pContext))
4103         return 0;
4104 
4105     while (!MatchVart(pContext))
4106     {
4107         if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4108             return 0;
4109     }
4110 
4111     return 1;
4112 }
4113 
4114 template <int x> int CGreedyElxT <x> ::MatchNext(CContext * pContext) const
4115 {
4116     if (MatchNextVart(pContext))
4117         return 1;
4118 
4119     if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4120         return 0;
4121 
4122     while (!MatchVart(pContext))
4123     {
4124         if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4125             return 0;
4126     }
4127 
4128     return 1;
4129 }
4130 
4131 template <int x> int CGreedyElxT <x> ::MatchVart(CContext * pContext) const
4132 {
4133     int n = 0;
4134     int nbegin00 = pContext->m_nCurrentPos;
4135     int nsize = pContext->m_stack.GetSize();
4136     int ncsize = pContext->m_capturestack.GetSize();
4137 
4138     while (n < m_nvart && CRepeatElx::MatchForward(pContext))
4139     {
4140         n++;
4141     }
4142 
4143     pContext->m_stack.Push(ncsize);
4144     pContext->m_stack.Push(nsize);
4145     pContext->m_stack.Push(pContext->m_nCurrentPos);
4146     pContext->m_stack.Push(1);
4147     pContext->m_stack.Push(nbegin00);
4148     pContext->m_stack.Push(n);
4149 
4150     return 1;
4151 }
4152 
4153 template <int x> int CGreedyElxT <x> ::MatchNextVart(CContext * pContext) const
4154 {
4155     int n, nbegin00, nsize, ncsize;
4156     CSortedBufferT <int> nbegin99;
4157     pContext->m_stack.Pop(n);
4158     pContext->m_stack.Pop(nbegin00);
4159     pContext->m_stack.Pop(nbegin99);
4160     pContext->m_stack.Pop(nsize);
4161     pContext->m_stack.Pop(ncsize);
4162 
4163     if (n == 0) return 0;
4164 
4165     int n0 = n;
4166 
4167     if (!CRepeatElxT<x>::m_pelx->MatchNext(pContext))
4168     {
4169         n--;
4170     }
4171 
4172     // not to re-match
4173     else if (pContext->m_nCurrentPos == nbegin00)
4174     {
4175         pContext->m_stack.Restore(nsize);
4176         pContext->m_capturestack.Restore(ncsize);
4177         pContext->m_nCurrentPos = nbegin00;
4178 
4179         return 0;
4180     }
4181 
4182     // fix 2012-10-26, thanks to chenlx01@sohu.com
4183     else
4184     {
4185         CContextShot shot(pContext);
4186 
4187         while (n < m_nvart && CRepeatElx::MatchForward(pContext))
4188         {
4189             n++;
4190         }
4191 
4192         if (nbegin99.Find(pContext->m_nCurrentPos) >= 0)
4193         {
4194             shot.Restore(pContext);
4195             n = n0;
4196         }
4197         else
4198         {
4199             nbegin99.Add(pContext->m_nCurrentPos);
4200         }
4201     }
4202 
4203     pContext->m_stack.Push(ncsize);
4204     pContext->m_stack.Push(nsize);
4205     pContext->m_stack.Push(nbegin99);
4206     pContext->m_stack.Push(nbegin00);
4207     pContext->m_stack.Push(n);
4208 
4209     return 1;
4210 }
4211 
4212 // indepelx.cpp: implementation of the CIndependentElx class.
4213 //
4214 template <int x> CIndependentElxT <x> ::CIndependentElxT(ElxInterface * pelx)
4215 {
4216     m_pelx = pelx;
4217 }
4218 
4219 template <int x> int CIndependentElxT <x> ::Match(CContext * pContext) const
4220 {
4221     int nbegin = pContext->m_nCurrentPos;
4222     int nsize = pContext->m_stack.GetSize();
4223     int ncsize = pContext->m_capturestack.GetSize();
4224 
4225     // match
4226     int bsucc = m_pelx->Match(pContext);
4227 
4228     // status
4229     pContext->m_stack.Restore(nsize);
4230 
4231     if (bsucc)
4232     {
4233         pContext->m_stack.Push(nbegin);
4234         pContext->m_stack.Push(ncsize);
4235     }
4236 
4237     return bsucc;
4238 }
4239 
4240 template <int x> int CIndependentElxT <x> ::MatchNext(CContext * pContext) const
4241 {
4242     int nbegin = 0, ncsize = 0;
4243 
4244     pContext->m_stack.Pop(ncsize);
4245     pContext->m_stack.Pop(nbegin);
4246 
4247     pContext->m_capturestack.Restore(ncsize);
4248     pContext->m_nCurrentPos = nbegin;
4249 
4250     return 0;
4251 }
4252 
4253 // listelx.cpp: implementation of the CListElx class.
4254 //
4255 template <int x> CListElxT <x> ::CListElxT(int brightleft)
4256 {
4257     m_brightleft = brightleft;
4258 }
4259 
4260 template <int x> int CListElxT <x> ::Match(CContext * pContext) const
4261 {
4262     if (m_elxlist.GetSize() == 0)
4263         return 1;
4264 
4265     // prepare
4266     int bol = m_brightleft ? m_elxlist.GetSize() : -1;
4267     int stp = m_brightleft ? -1 : 1;
4268     int eol = m_brightleft ? -1 : m_elxlist.GetSize();
4269 
4270     // from first
4271     int n = bol + stp;
4272 
4273     // match all
4274     while (n != eol)
4275     {
4276         if (m_elxlist[n]->Match(pContext))
4277         {
4278             n += stp;
4279         }
4280         else
4281         {
4282             n -= stp;
4283 
4284             while (n != bol && !m_elxlist[n]->MatchNext(pContext))
4285                 n -= stp;
4286 
4287             if (n != bol)
4288                 n += stp;
4289             else
4290                 return 0;
4291         }
4292     }
4293 
4294     return 1;
4295 }
4296 
4297 template <int x> int CListElxT <x> ::MatchNext(CContext * pContext) const
4298 {
4299     if (m_elxlist.GetSize() == 0)
4300         return 0;
4301 
4302     // prepare
4303     int bol = m_brightleft ? m_elxlist.GetSize() : -1;
4304     int stp = m_brightleft ? -1 : 1;
4305     int eol = m_brightleft ? -1 : m_elxlist.GetSize();
4306 
4307     // from last
4308     int n = eol - stp;
4309 
4310     while (n != bol && !m_elxlist[n]->MatchNext(pContext))
4311         n -= stp;
4312 
4313     if (n != bol)
4314         n += stp;
4315     else
4316         return 0;
4317 
4318     // match rest
4319     while (n != eol)
4320     {
4321         if (m_elxlist[n]->Match(pContext))
4322         {
4323             n += stp;
4324         }
4325         else
4326         {
4327             n -= stp;
4328 
4329             while (n != bol && !m_elxlist[n]->MatchNext(pContext))
4330                 n -= stp;
4331 
4332             if (n != bol)
4333                 n += stp;
4334             else
4335                 return 0;
4336         }
4337     }
4338 
4339     return 1;
4340 }
4341 
4342 // mresult.cpp: implementation of the MatchResult class.
4343 //
4344 template <int x> MatchResultT <x> ::MatchResultT(CContext * pContext, int nMaxNumber)
4345 {
4346     if (pContext != 0)
4347     {
4348         m_result.Prepare(nMaxNumber * 2 + 3, -1);
4349 
4350         // matched
4351         m_result[0] = 1;
4352         m_result[1] = nMaxNumber;
4353 
4354         for (int n = 0; n <= nMaxNumber; n++)
4355         {
4356             int index = pContext->m_captureindex[n];
4357             //if( index < 0 ) continue;
4358             if (!CBracketElxT<char>::CheckCaptureIndex(index, pContext, n)) continue;
4359 
4360             // check enclosed
4361             int pos1 = pContext->m_capturestack[index + 1];
4362             int pos2 = pContext->m_capturestack[index + 2];
4363 
4364             // info
4365             m_result[n * 2 + 2] = pos1 < pos2 ? pos1 : pos2;
4366             m_result[n * 2 + 3] = pos1 < pos2 ? pos2 : pos1;
4367         }
4368     }
4369 }
4370 
4371 template <int x> inline int MatchResultT <x> ::IsMatched() const
4372 {
4373     return m_result.At(0, 0);
4374 }
4375 
4376 template <int x> inline int MatchResultT <x> ::MaxGroupNumber() const
4377 {
4378     return m_result.At(1, 0);
4379 }
4380 
4381 template <int x> inline int MatchResultT <x> ::GetStart() const
4382 {
4383     return m_result.At(2, -1);
4384 }
4385 
4386 template <int x> inline int MatchResultT <x> ::GetEnd() const
4387 {
4388     return m_result.At(3, -1);
4389 }
4390 
4391 template <int x> inline int MatchResultT <x> ::GetGroupStart(int nGroupNumber) const
4392 {
4393     return m_result.At(2 + nGroupNumber * 2, -1);
4394 }
4395 
4396 template <int x> inline int MatchResultT <x> ::GetGroupEnd(int nGroupNumber) const
4397 {
4398     return m_result.At(2 + nGroupNumber * 2 + 1, -1);
4399 }
4400 
4401 template <int x> MatchResultT <x> & MatchResultT <x> :: operator = (const MatchResultT <x> & result)
4402 {
4403     m_result.Restore(0);
4404     if (result.m_result.GetSize() > 0) m_result.Append(result.m_result.GetBuffer(), result.m_result.GetSize());
4405 
4406     return *this;
4407 }
4408 
4409 // posselx.cpp: implementation of the CPossessiveElx class.
4410 //
4411 template <int x> CPossessiveElxT <x> ::CPossessiveElxT(ElxInterface * pelx, int nmin, int nmax) : CGreedyElxT <x>(pelx, nmin, nmax)
4412 {
4413 }
4414 
4415 template <int x> int CPossessiveElxT <x> ::Match(CContext * pContext) const
4416 {
4417     int nbegin = pContext->m_nCurrentPos;
4418     int nsize = pContext->m_stack.GetSize();
4419     int ncsize = pContext->m_capturestack.GetSize();
4420     int bsucc = 1;
4421 
4422     // match
4423     if (!CRepeatElxT <x> ::MatchFixed(pContext))
4424     {
4425         bsucc = 0;
4426     }
4427     else
4428     {
4429         while (!CGreedyElxT <x> ::MatchVart(pContext))
4430         {
4431             if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4432             {
4433                 bsucc = 0;
4434                 break;
4435             }
4436         }
4437     }
4438 
4439     // status
4440     pContext->m_stack.Restore(nsize);
4441 
4442     if (bsucc)
4443     {
4444         pContext->m_stack.Push(nbegin);
4445         pContext->m_stack.Push(ncsize);
4446     }
4447 
4448     return bsucc;
4449 }
4450 
4451 template <int x> int CPossessiveElxT <x> ::MatchNext(CContext * pContext) const
4452 {
4453     int nbegin = 0, ncsize = 0;
4454 
4455     pContext->m_stack.Pop(ncsize);
4456     pContext->m_stack.Pop(nbegin);
4457 
4458     pContext->m_capturestack.Restore(ncsize);
4459     pContext->m_nCurrentPos = nbegin;
4460 
4461     return 0;
4462 }
4463 
4464 // reluctx.cpp: implementation of the CReluctantElx class.
4465 //
4466 template <int x> CReluctantElxT <x> ::CReluctantElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x>(pelx, nmin)
4467 {
4468     m_nvart = nmax - nmin;
4469 }
4470 
4471 template <int x> int CReluctantElxT <x> ::Match(CContext * pContext) const
4472 {
4473     if (!CRepeatElxT <x> ::MatchFixed(pContext))
4474         return 0;
4475 
4476     while (!MatchVart(pContext))
4477     {
4478         if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4479             return 0;
4480     }
4481 
4482     return 1;
4483 }
4484 
4485 template <int x> int CReluctantElxT <x> ::MatchNext(CContext * pContext) const
4486 {
4487     if (MatchNextVart(pContext))
4488         return 1;
4489 
4490     if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4491         return 0;
4492 
4493     while (!MatchVart(pContext))
4494     {
4495         if (!CRepeatElxT <x> ::MatchNextFixed(pContext))
4496             return 0;
4497     }
4498 
4499     return 1;
4500 }
4501 
4502 template <int x> int CReluctantElxT <x> ::MatchVart(CContext * pContext) const
4503 {
4504     pContext->m_stack.Push(0);
4505 
4506     return 1;
4507 }
4508 
4509 template <int x> int CReluctantElxT <x> ::MatchNextVart(CContext * pContext) const
4510 {
4511     int n = 0, nbegin = pContext->m_nCurrentPos;
4512 
4513     pContext->m_stack.Pop(n);
4514 
4515     if (n < m_nvart && CRepeatElxT <x> ::m_pelx->Match(pContext))
4516     {
4517         while (pContext->m_nCurrentPos == nbegin)
4518         {
4519             if (!CRepeatElxT <x> ::m_pelx->MatchNext(pContext)) break;
4520         }
4521 
4522         if (pContext->m_nCurrentPos != nbegin)
4523         {
4524             n++;
4525 
4526             pContext->m_stack.Push(nbegin);
4527             pContext->m_stack.Push(n);
4528 
4529             return 1;
4530         }
4531     }
4532 
4533     while (n > 0)
4534     {
4535         pContext->m_stack.Pop(nbegin);
4536 
4537         while (CRepeatElxT <x> ::m_pelx->MatchNext(pContext))
4538         {
4539             if (pContext->m_nCurrentPos != nbegin)
4540             {
4541                 pContext->m_stack.Push(nbegin);
4542                 pContext->m_stack.Push(n);
4543 
4544                 return 1;
4545             }
4546         }
4547 
4548         n--;
4549     }
4550 
4551     return 0;
4552 }
4553 
4554 // repeatx.cpp: implementation of the CRepeatElx class.
4555 //
4556 template <int x> CRepeatElxT <x> ::CRepeatElxT(ElxInterface * pelx, int ntimes)
4557 {
4558     m_pelx = pelx;
4559     m_nfixed = ntimes;
4560 }
4561 
4562 template <int x> int CRepeatElxT <x> ::Match(CContext * pContext) const
4563 {
4564     return MatchFixed(pContext);
4565 }
4566 
4567 template <int x> int CRepeatElxT <x> ::MatchNext(CContext * pContext) const
4568 {
4569     return MatchNextFixed(pContext);
4570 }
4571 
4572 template <int x> int CRepeatElxT <x> ::MatchFixed(CContext * pContext) const
4573 {
4574     if (m_nfixed == 0)
4575         return 1;
4576 
4577     int n = 0;
4578 
4579     while (n < m_nfixed)
4580     {
4581         if (m_pelx->Match(pContext))
4582         {
4583             n++;
4584         }
4585         else
4586         {
4587             n--;
4588 
4589             while (n >= 0 && !m_pelx->MatchNext(pContext))
4590                 n--;
4591 
4592             if (n >= 0)
4593                 n++;
4594             else
4595                 return 0;
4596         }
4597     }
4598 
4599     return 1;
4600 }
4601 
4602 template <int x> int CRepeatElxT <x> ::MatchNextFixed(CContext * pContext) const
4603 {
4604     if (m_nfixed == 0)
4605         return 0;
4606 
4607     // from last
4608     int n = m_nfixed - 1;
4609 
4610     while (n >= 0 && !m_pelx->MatchNext(pContext))
4611         n--;
4612 
4613     if (n >= 0)
4614         n++;
4615     else
4616         return 0;
4617 
4618     // match rest
4619     while (n < m_nfixed)
4620     {
4621         if (m_pelx->Match(pContext))
4622         {
4623             n++;
4624         }
4625         else
4626         {
4627             n--;
4628 
4629             while (n >= 0 && !m_pelx->MatchNext(pContext))
4630                 n--;
4631 
4632             if (n >= 0)
4633                 n++;
4634             else
4635                 return 0;
4636         }
4637     }
4638 
4639     return 1;
4640 }
4641 
4642 // Regexp
4643 typedef CRegexpT <char> CRegexpA;
4644 typedef CRegexpT <unsigned short> CRegexpW;
4645 
4646 #if defined(_UNICODE) || defined(UNICODE)
4647 typedef CRegexpW CRegexp;
4648 #else
4649 typedef CRegexpA CRegexp;
4650 #endif
4651 
4652 #endif

 

posted @ 2016-09-22 19:37  BelFuture  阅读(447)  评论(0编辑  收藏  举报
The horizon of life is broadened chiefly by the enlargement of the heart.