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