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