embox

Форк
0
667 строк · 17.0 Кб
1
/***************************************************************
2
	T-Rex a tiny regular expression library
3

4
	Copyright (C) 2003-2006 Alberto Demichelis
5

6
	This software is provided 'as-is', without any express
7
	or implied warranty. In no event will the authors be held
8
	liable for any damages arising from the use of this software.
9

10
	Permission is granted to anyone to use this software for
11
	any purpose, including commercial applications, and to alter
12
	it and redistribute it freely, subject to the following restrictions:
13

14
		1. The origin of this software must not be misrepresented;
15
		you must not claim that you wrote the original software.
16
		If you use this software in a product, an acknowledgment
17
		in the product documentation would be appreciated but
18
		is not required.
19

20
		2. Altered source versions must be plainly marked as such,
21
		and must not be misrepresented as being the original software.
22

23
		3. This notice may not be removed or altered from any
24
		source distribution.
25

26
****************************************************************/
27
#include <string.h>
28
#include <stdlib.h>
29
#include <ctype.h>
30
#include <setjmp.h>
31
#include "trex.h"
32

33
#ifdef _UINCODE
34
#define scisprint iswprint
35
#define scstrlen wcslen
36
#define scprintf wprintf
37
#define _SC(x) L(x)
38
#else
39
#define scisprint isprint
40
#define scstrlen strlen
41
#define scprintf printf
42
#define _SC(x) (x)
43
#endif
44

45
#ifdef _DEBUG
46
#include <stdio.h>
47

48
static const TRexChar *g_nnames[] =
49
{
50
	_SC("NONE"),_SC("OP_GREEDY"),	_SC("OP_OR"),
51
	_SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),	_SC("OP_CLASS"),
52
	_SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
53
	_SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
54
};
55

56
#endif
57
#define OP_GREEDY		(MAX_CHAR+1) // * + ? {n}
58
#define OP_OR			(MAX_CHAR+2)
59
#define OP_EXPR			(MAX_CHAR+3) //parentesis ()
60
#define OP_NOCAPEXPR	(MAX_CHAR+4) //parentesis (?:)
61
#define OP_DOT			(MAX_CHAR+5)
62
#define OP_CLASS		(MAX_CHAR+6)
63
#define OP_CCLASS		(MAX_CHAR+7)
64
#define OP_NCLASS		(MAX_CHAR+8) //negates class the [^
65
#define OP_RANGE		(MAX_CHAR+9)
66
#define OP_CHAR			(MAX_CHAR+10)
67
#define OP_EOL			(MAX_CHAR+11)
68
#define OP_BOL			(MAX_CHAR+12)
69
#define OP_WB			(MAX_CHAR+13)
70

71
#define TREX_SYMBOL_ANY_CHAR ('.')
72
#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
73
#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
74
#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
75
#define TREX_SYMBOL_BRANCH ('|')
76
#define TREX_SYMBOL_END_OF_STRING ('$')
77
#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
78
#define TREX_SYMBOL_ESCAPE_CHAR ('\\')
79

80

81
typedef int TRexNodeType;
82

83
typedef struct tagTRexNode{
84
	TRexNodeType type;
85
	int left;
86
	int right;
87
	int next;
88
}TRexNode;
89

90
struct TRex{
91
	const TRexChar *_eol;
92
	const TRexChar *_bol;
93
	const TRexChar *_p;
94
	int _first;
95
	int _op;
96
	TRexNode *_nodes;
97
	int _nallocated;
98
	int _nsize;
99
	int _nsubexpr;
100
	TRexMatch *_matches;
101
	int _currsubexp;
102
	void *_jmpbuf;
103
	TRexChar *_error;
104
};
105

106
static int trex_list(TRex *exp);
107

108
static int trex_newnode(TRex *exp, TRexNodeType type)
109
{
110
	TRexNode n;
111
	int newid;
112
	n.type = type;
113
	n.next = n.right = n.left = -1;
114
	if(type == OP_EXPR)
115
		n.right = exp->_nsubexpr++;
116
	if(exp->_nallocated < (exp->_nsize + 1)) {
117
		//int oldsize = exp->_nallocated;
118
		exp->_nallocated *= 2;
119
		exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
120
	}
121
	exp->_nodes[exp->_nsize++] = n;
122
	newid = exp->_nsize - 1;
123
	return (int)newid;
124
}
125

126
static void trex_error(TRex *exp,const TRexChar *error)
127
{
128
	if(exp->_error) strcpy(exp->_error, error);
129
	longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
130
}
131

132
static void trex_expect(TRex *exp, int n){
133
	if((*exp->_p) != n)
134
		trex_error(exp, _SC("expected paren"));
135
	exp->_p++;
136
}
137

138
static TRexChar trex_escapechar(TRex *exp)
139
{
140
	if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
141
		exp->_p++;
142
		switch(*exp->_p) {
143
		case 'v': exp->_p++; return '\v';
144
		case 'n': exp->_p++; return '\n';
145
		case 't': exp->_p++; return '\t';
146
		case 'r': exp->_p++; return '\r';
147
		case 'f': exp->_p++; return '\f';
148
		default: return (*exp->_p++);
149
		}
150
	} else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
151
	return (*exp->_p++);
152
}
153

154
static int trex_charclass(TRex *exp,int classid)
155
{
156
	int n = trex_newnode(exp,OP_CCLASS);
157
	exp->_nodes[n].left = classid;
158
	return n;
159
}
160

161
static int trex_charnode(TRex *exp,TRexBool isclass)
162
{
163
	TRexChar t;
164
	if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
165
		exp->_p++;
166
		switch(*exp->_p) {
167
			case 'n': exp->_p++; return trex_newnode(exp,'\n');
168
			case 't': exp->_p++; return trex_newnode(exp,'\t');
169
			case 'r': exp->_p++; return trex_newnode(exp,'\r');
170
			case 'f': exp->_p++; return trex_newnode(exp,'\f');
171
			case 'v': exp->_p++; return trex_newnode(exp,'\v');
172
			case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
173
			case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
174
			case 'p': case 'P': case 'l': case 'u':
175
				{
176
				t = *exp->_p; exp->_p++;
177
				return trex_charclass(exp,t);
178
				}
179
			case 'b':
180
			case 'B':
181
				if(!isclass) {
182
					int node = trex_newnode(exp,OP_WB);
183
					exp->_nodes[node].left = *exp->_p;
184
					exp->_p++;
185
					return node;
186
				} //else default
187
			default:
188
				t = *exp->_p; exp->_p++;
189
				return trex_newnode(exp,t);
190
		}
191
	}
192
	else if(!scisprint(*exp->_p)) {
193

194
		trex_error(exp,_SC("letter expected"));
195
	}
196
	t = *exp->_p; exp->_p++;
197
	return trex_newnode(exp,t);
198
}
199
static int trex_class(TRex *exp)
200
{
201
	int ret = -1;
202
	int first = -1,chain;
203
	if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
204
		ret = trex_newnode(exp,OP_NCLASS);
205
		exp->_p++;
206
	}else ret = trex_newnode(exp,OP_CLASS);
207

208
	if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
209
	chain = ret;
210
	while(*exp->_p != ']' && exp->_p != exp->_eol) {
211
		if(*exp->_p == '-' && first != -1){
212
			int r,t;
213
			if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
214
			r = trex_newnode(exp,OP_RANGE);
215
			if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
216
			if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
217
			exp->_nodes[r].left = exp->_nodes[first].type;
218
			t = trex_escapechar(exp);
219
			exp->_nodes[r].right = t;
220
            exp->_nodes[chain].next = r;
221
			chain = r;
222
			first = -1;
223
		}
224
		else{
225
			if(first!=-1){
226
				int c = first;
227
				exp->_nodes[chain].next = c;
228
				chain = c;
229
				first = trex_charnode(exp,TRex_True);
230
			}
231
			else{
232
				first = trex_charnode(exp,TRex_True);
233
			}
234
		}
235
	}
236
	if(first!=-1){
237
		int c = first;
238
		exp->_nodes[chain].next = c;
239
		chain = c;
240
		first = -1;
241
	}
242
	/* hack? */
243
	exp->_nodes[ret].left = exp->_nodes[ret].next;
244
	exp->_nodes[ret].next = -1;
245
	return ret;
246
}
247

248
static int trex_parsenumber(TRex *exp)
249
{
250
	int ret = *exp->_p-'0';
251
	int positions = 10;
252
	exp->_p++;
253
	while(isdigit(*exp->_p)) {
254
		ret = ret*10+(*exp->_p++-'0');
255
		if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
256
		positions *= 10;
257
	};
258
	return ret;
259
}
260

261
static int trex_element(TRex *exp)
262
{
263
	int ret = -1;
264
	switch(*exp->_p)
265
	{
266
	case '(': {
267
		int expr,newn;
268
		exp->_p++;
269

270

271
		if(*exp->_p =='?') {
272
			exp->_p++;
273
			trex_expect(exp,':');
274
			expr = trex_newnode(exp,OP_NOCAPEXPR);
275
		}
276
		else
277
			expr = trex_newnode(exp,OP_EXPR);
278
		newn = trex_list(exp);
279
		exp->_nodes[expr].left = newn;
280
		ret = expr;
281
		trex_expect(exp,')');
282
			  }
283
			  break;
284
	case '[':
285
		exp->_p++;
286
		ret = trex_class(exp);
287
		trex_expect(exp,']');
288
		break;
289
	case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
290
	case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
291
	default:
292
		ret = trex_charnode(exp,TRex_False);
293
		break;
294
	}
295

296
	{
297
		TRexBool isgreedy = TRex_False;
298
		unsigned short p0 = 0, p1 = 0;
299
		switch(*exp->_p){
300
			case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
301
			case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
302
			case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
303
			case '{':
304
				exp->_p++;
305
				if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
306
				p0 = (unsigned short)trex_parsenumber(exp);
307
				/*******************************/
308
				switch(*exp->_p) {
309
			case '}':
310
				p1 = p0; exp->_p++;
311
				break;
312
			case ',':
313
				exp->_p++;
314
				p1 = 0xFFFF;
315
				if(isdigit(*exp->_p)){
316
					p1 = (unsigned short)trex_parsenumber(exp);
317
				}
318
				trex_expect(exp,'}');
319
				break;
320
			default:
321
				trex_error(exp,_SC(", or } expected"));
322
		}
323
		/*******************************/
324
		isgreedy = TRex_True;
325
		break;
326

327
		}
328
		if(isgreedy) {
329
			//int op;
330
			int nnode = trex_newnode(exp,OP_GREEDY);
331
			//op = OP_GREEDY;
332
			exp->_nodes[nnode].left = ret;
333
			exp->_nodes[nnode].right = ((p0)<<16)|p1;
334
			ret = nnode;
335
		}
336
	}
337
	if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
338
		int nnode = trex_element(exp);
339
		exp->_nodes[ret].next = nnode;
340
	}
341

342
	return ret;
343
}
344

345
static int trex_list(TRex *exp)
346
{
347
	int ret=-1,e;
348
	if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
349
		exp->_p++;
350
		ret = trex_newnode(exp,OP_BOL);
351
	}
352
	e = trex_element(exp);
353
	if(ret != -1) {
354
		exp->_nodes[ret].next = e;
355
	}
356
	else ret = e;
357

358
	if(*exp->_p == TREX_SYMBOL_BRANCH) {
359
		int temp,tright;
360
		exp->_p++;
361
		temp = trex_newnode(exp,OP_OR);
362
		exp->_nodes[temp].left = ret;
363
		tright = trex_list(exp);
364
		exp->_nodes[temp].right = tright;
365
		ret = temp;
366
	}
367
	return ret;
368
}
369

370
static TRexBool trex_matchcclass(int cclass,TRexChar c)
371
{
372
	switch(cclass) {
373
	case 'a': return isalpha(c)?TRex_True:TRex_False;
374
	case 'A': return !isalpha(c)?TRex_True:TRex_False;
375
	case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
376
	case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
377
	case 's': return isspace(c)?TRex_True:TRex_False;
378
	case 'S': return !isspace(c)?TRex_True:TRex_False;
379
	case 'd': return isdigit(c)?TRex_True:TRex_False;
380
	case 'D': return !isdigit(c)?TRex_True:TRex_False;
381
	case 'x': return isxdigit(c)?TRex_True:TRex_False;
382
	case 'X': return !isxdigit(c)?TRex_True:TRex_False;
383
	case 'c': return iscntrl(c)?TRex_True:TRex_False;
384
	case 'C': return !iscntrl(c)?TRex_True:TRex_False;
385
	case 'p': return ispunct(c)?TRex_True:TRex_False;
386
	case 'P': return !ispunct(c)?TRex_True:TRex_False;
387
	case 'l': return islower(c)?TRex_True:TRex_False;
388
	case 'u': return isupper(c)?TRex_True:TRex_False;
389
	}
390
	return TRex_False; /*cannot happen*/
391
}
392

393
static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
394
{
395
	do {
396
		switch(node->type) {
397
			case OP_RANGE:
398
				if(c >= node->left && c <= node->right) return TRex_True;
399
				break;
400
			case OP_CCLASS:
401
				if(trex_matchcclass(node->left,c)) return TRex_True;
402
				break;
403
			default:
404
				if(c == node->type)return TRex_True;
405
		}
406
	} while((node->next != -1) && (node = &exp->_nodes[node->next]));
407
	return TRex_False;
408
}
409

410
static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
411
{
412

413
	TRexNodeType type = node->type;
414
	switch(type) {
415
	case OP_GREEDY: {
416
		//TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
417
		TRexNode *greedystop = NULL;
418
		int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
419
		const TRexChar *s=str, *good = str;
420

421
		if(node->next != -1) {
422
			greedystop = &exp->_nodes[node->next];
423
		}
424
		else {
425
			greedystop = next;
426
		}
427

428
		while((nmaches == 0xFFFF || nmaches < p1)) {
429

430
			const TRexChar *stop;
431
			if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
432
				break;
433
			nmaches++;
434
			good=s;
435
			if(greedystop) {
436
				//checks that 0 matches satisfy the expression(if so skips)
437
				//if not would always stop(for instance if is a '?')
438
				if(greedystop->type != OP_GREEDY ||
439
				(greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
440
				{
441
					TRexNode *gnext = NULL;
442
					if(greedystop->next != -1) {
443
						gnext = &exp->_nodes[greedystop->next];
444
					}else if(next && next->next != -1){
445
						gnext = &exp->_nodes[next->next];
446
					}
447
					stop = trex_matchnode(exp,greedystop,s,gnext);
448
					if(stop) {
449
						//if satisfied stop it
450
						if(p0 == p1 && p0 == nmaches) break;
451
						else if(nmaches >= p0 && p1 == 0xFFFF) break;
452
						else if(nmaches >= p0 && nmaches <= p1) break;
453
					}
454
				}
455
			}
456

457
			if(s >= exp->_eol)
458
				break;
459
		}
460
		if(p0 == p1 && p0 == nmaches) return good;
461
		else if(nmaches >= p0 && p1 == 0xFFFF) return good;
462
		else if(nmaches >= p0 && nmaches <= p1) return good;
463
		return NULL;
464
	}
465
	case OP_OR: {
466
			const TRexChar *asd = str;
467
			TRexNode *temp=&exp->_nodes[node->left];
468
			while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
469
				if(temp->next != -1)
470
					temp = &exp->_nodes[temp->next];
471
				else
472
					return asd;
473
			}
474
			asd = str;
475
			temp = &exp->_nodes[node->right];
476
			while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
477
				if(temp->next != -1)
478
					temp = &exp->_nodes[temp->next];
479
				else
480
					return asd;
481
			}
482
			return NULL;
483
			break;
484
	}
485
	case OP_EXPR:
486
	case OP_NOCAPEXPR:{
487
			TRexNode *n = &exp->_nodes[node->left];
488
			const TRexChar *cur = str;
489
			int capture = -1;
490
			if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
491
				capture = exp->_currsubexp;
492
				exp->_matches[capture].begin = cur;
493
				exp->_currsubexp++;
494
			}
495

496
			do {
497
				TRexNode *subnext = NULL;
498
				if(n->next != -1) {
499
					subnext = &exp->_nodes[n->next];
500
				}else {
501
					subnext = next;
502
				}
503
				if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
504
					if(capture != -1){
505
						exp->_matches[capture].begin = 0;
506
						exp->_matches[capture].len = 0;
507
					}
508
					return NULL;
509
				}
510
			} while((n->next != -1) && (n = &exp->_nodes[n->next]));
511

512
			if(capture != -1)
513
				exp->_matches[capture].len = cur - exp->_matches[capture].begin;
514
			return cur;
515
	}
516
	case OP_WB:
517
		if((str == exp->_bol && !isspace(*str))
518
		 || (str == exp->_eol && !isspace(*(str-1)))
519
		 || (!isspace(*str) && isspace(*(str+1)))
520
		 || (isspace(*str) && !isspace(*(str+1))) ) {
521
			return (node->left == 'b')?str:NULL;
522
		}
523
		return (node->left == 'b')?NULL:str;
524
	case OP_BOL:
525
		if(str == exp->_bol) return str;
526
		return NULL;
527
	case OP_EOL:
528
		if(str == exp->_eol) return str;
529
		return NULL;
530
	case OP_DOT:{
531
		str++;
532
				}
533
		return str;
534
	case OP_NCLASS:
535
	case OP_CLASS:
536
		if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
537
			str++;
538
			return str;
539
		}
540
		return NULL;
541
	case OP_CCLASS:
542
		if(trex_matchcclass(node->left,*str)) {
543
			str++;
544
			return str;
545
		}
546
		return NULL;
547
	default: /* char */
548
		if(*str != node->type) return NULL;
549
		str++;
550
		return str;
551
	}
552
	return NULL;
553
}
554

555
/* public api */
556
TRex *trex_compile(const TRexChar *pattern,TRexChar *error)
557
{
558
	TRex *exp = (TRex *)malloc(sizeof(TRex));
559
	exp->_eol = exp->_bol = NULL;
560
	exp->_p = pattern;
561
	exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
562
	exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
563
	exp->_nsize = 0;
564
	exp->_matches = 0;
565
	exp->_nsubexpr = 0;
566
	exp->_first = trex_newnode(exp,OP_EXPR);
567
	exp->_error = error;
568
	exp->_jmpbuf = malloc(sizeof(jmp_buf));
569
	if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
570
		int res = trex_list(exp);
571
		exp->_nodes[exp->_first].left = res;
572
		if(*exp->_p!='\0')
573
			trex_error(exp,_SC("unexpected character"));
574
#ifdef _DEBUG
575
		{
576
			int nsize,i;
577
			TRexNode *t;
578
			nsize = exp->_nsize;
579
			t = &exp->_nodes[0];
580
			scprintf(_SC("\n"));
581
			for(i = 0;i < nsize; i++) {
582
				if(exp->_nodes[i].type>MAX_CHAR)
583
					scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
584
				else
585
					scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
586
				scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
587
			}
588
			scprintf(_SC("\n"));
589
		}
590
#endif
591
		exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
592
		memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
593
	}
594
	else{
595
		trex_free(exp);
596
		return NULL;
597
	}
598
	return exp;
599
}
600

601
void trex_free(TRex *exp)
602
{
603
	if(exp)	{
604
		if(exp->_nodes) free(exp->_nodes);
605
		if(exp->_jmpbuf) free(exp->_jmpbuf);
606
		if(exp->_matches) free(exp->_matches);
607
		free(exp);
608
	}
609
}
610

611
TRexBool trex_match(TRex* exp,const TRexChar* text)
612
{
613
	const TRexChar* res = NULL;
614
	exp->_bol = text;
615
	exp->_eol = text + scstrlen(text);
616
	exp->_currsubexp = 0;
617
	res = trex_matchnode(exp,exp->_nodes,text,NULL);
618
	if(res == NULL || res != exp->_eol)
619
		return TRex_False;
620
	return TRex_True;
621
}
622

623
TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
624
{
625
	const TRexChar *cur = NULL;
626
	int node = exp->_first;
627
	if(text_begin >= text_end) return TRex_False;
628
	exp->_bol = text_begin;
629
	exp->_eol = text_end;
630
	do {
631
		cur = text_begin;
632
		while(node != -1) {
633
			exp->_currsubexp = 0;
634
			cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
635
			if(!cur)
636
				break;
637
			node = exp->_nodes[node].next;
638
		}
639
		text_begin++;
640
	} while(cur == NULL && text_begin != text_end);
641

642
	if(cur == NULL)
643
		return TRex_False;
644

645
	--text_begin;
646

647
	if(out_begin) *out_begin = text_begin;
648
	if(out_end) *out_end = cur;
649
	return TRex_True;
650
}
651

652
TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
653
{
654
	return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
655
}
656

657
int trex_getsubexpcount(TRex* exp)
658
{
659
	return exp->_nsubexpr;
660
}
661

662
TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
663
{
664
	if( n<0 || n >= exp->_nsubexpr) return TRex_False;
665
	*subexp = exp->_matches[n];
666
	return TRex_True;
667
}
668

669

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.