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