Update SQUIRREL to 2.2.5
[supertux.git] / external / squirrel / sqstdlib / sqstdrex.cpp
1 /* see copyright notice in squirrel.h */\r
2 #include <squirrel.h>\r
3 #include <string.h>\r
4 #include <ctype.h>\r
5 #include <setjmp.h>\r
6 #include "sqstdstring.h"\r
7 \r
8 #ifdef _UINCODE\r
9 #define scisprint iswprint\r
10 #else\r
11 #define scisprint isprint\r
12 #endif\r
13 \r
14 #ifdef _DEBUG\r
15 #include <stdio.h>\r
16 \r
17 static const SQChar *g_nnames[] =\r
18 {\r
19         _SC("NONE"),_SC("OP_GREEDY"),   _SC("OP_OR"),\r
20         _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),       _SC("OP_CLASS"),\r
21         _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
22         _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
23 };\r
24 \r
25 #endif\r
26 \r
27 #define OP_GREEDY               (MAX_CHAR+1) // * + ? {n}\r
28 #define OP_OR                   (MAX_CHAR+2)\r
29 #define OP_EXPR                 (MAX_CHAR+3) //parentesis ()\r
30 #define OP_NOCAPEXPR    (MAX_CHAR+4) //parentesis (?:)\r
31 #define OP_DOT                  (MAX_CHAR+5)\r
32 #define OP_CLASS                (MAX_CHAR+6)\r
33 #define OP_CCLASS               (MAX_CHAR+7)\r
34 #define OP_NCLASS               (MAX_CHAR+8) //negates class the [^\r
35 #define OP_RANGE                (MAX_CHAR+9)\r
36 #define OP_CHAR                 (MAX_CHAR+10)\r
37 #define OP_EOL                  (MAX_CHAR+11)\r
38 #define OP_BOL                  (MAX_CHAR+12)\r
39 #define OP_WB                   (MAX_CHAR+13)\r
40 \r
41 #define SQREX_SYMBOL_ANY_CHAR ('.')\r
42 #define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')\r
43 #define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')\r
44 #define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')\r
45 #define SQREX_SYMBOL_BRANCH ('|')\r
46 #define SQREX_SYMBOL_END_OF_STRING ('$')\r
47 #define SQREX_SYMBOL_BEGINNING_OF_STRING ('^')\r
48 #define SQREX_SYMBOL_ESCAPE_CHAR ('\\')\r
49 \r
50 \r
51 typedef int SQRexNodeType;\r
52 \r
53 typedef struct tagSQRexNode{\r
54         SQRexNodeType type;\r
55         SQInteger left;\r
56         SQInteger right;\r
57         SQInteger next;\r
58 }SQRexNode;\r
59 \r
60 struct SQRex{\r
61         const SQChar *_eol;\r
62         const SQChar *_bol;\r
63         const SQChar *_p;\r
64         SQInteger _first;\r
65         SQInteger _op;\r
66         SQRexNode *_nodes;\r
67         SQInteger _nallocated;\r
68         SQInteger _nsize;\r
69         SQInteger _nsubexpr;\r
70         SQRexMatch *_matches;\r
71         SQInteger _currsubexp;\r
72         void *_jmpbuf;\r
73         const SQChar **_error;\r
74 };\r
75 \r
76 static SQInteger sqstd_rex_list(SQRex *exp);\r
77 \r
78 static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\r
79 {\r
80         SQRexNode n;\r
81         n.type = type;\r
82         n.next = n.right = n.left = -1;\r
83         if(type == OP_EXPR)\r
84                 n.right = exp->_nsubexpr++;\r
85         if(exp->_nallocated < (exp->_nsize + 1)) {\r
86                 SQInteger oldsize = exp->_nallocated;\r
87                 exp->_nallocated *= 2;\r
88                 exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\r
89         }\r
90         exp->_nodes[exp->_nsize++] = n;\r
91         SQInteger newid = exp->_nsize - 1;\r
92         return (SQInteger)newid;\r
93 }\r
94 \r
95 static void sqstd_rex_error(SQRex *exp,const SQChar *error)\r
96 {\r
97         if(exp->_error) *exp->_error = error;\r
98         longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
99 }\r
100 \r
101 static void sqstd_rex_expect(SQRex *exp, SQInteger n){\r
102         if((*exp->_p) != n) \r
103                 sqstd_rex_error(exp, _SC("expected paren"));\r
104         exp->_p++;\r
105 }\r
106 \r
107 static SQChar sqstd_rex_escapechar(SQRex *exp)\r
108 {\r
109         if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\r
110                 exp->_p++;\r
111                 switch(*exp->_p) {\r
112                 case 'v': exp->_p++; return '\v';\r
113                 case 'n': exp->_p++; return '\n';\r
114                 case 't': exp->_p++; return '\t';\r
115                 case 'r': exp->_p++; return '\r';\r
116                 case 'f': exp->_p++; return '\f';\r
117                 default: return (*exp->_p++);\r
118                 }\r
119         } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));\r
120         return (*exp->_p++);\r
121 }\r
122 \r
123 static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\r
124 {\r
125         SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\r
126         exp->_nodes[n].left = classid;\r
127         return n;\r
128 }\r
129 \r
130 static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\r
131 {\r
132         SQChar t;\r
133         if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\r
134                 exp->_p++;\r
135                 switch(*exp->_p) {\r
136                         case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');\r
137                         case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');\r
138                         case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');\r
139                         case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');\r
140                         case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');\r
141                         case 'a': case 'A': case 'w': case 'W': case 's': case 'S': \r
142                         case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': \r
143                         case 'p': case 'P': case 'l': case 'u': \r
144                                 {\r
145                                 t = *exp->_p; exp->_p++; \r
146                                 return sqstd_rex_charclass(exp,t);\r
147                                 }\r
148                         case 'b': \r
149                         case 'B':\r
150                                 if(!isclass) {\r
151                                         SQInteger node = sqstd_rex_newnode(exp,OP_WB);\r
152                                         exp->_nodes[node].left = *exp->_p;\r
153                                         exp->_p++; \r
154                                         return node;\r
155                                 } //else default\r
156                         default: \r
157                                 t = *exp->_p; exp->_p++; \r
158                                 return sqstd_rex_newnode(exp,t);\r
159                 }\r
160         }\r
161         else if(!scisprint(*exp->_p)) {\r
162                 \r
163                 sqstd_rex_error(exp,_SC("letter expected"));\r
164         }\r
165         t = *exp->_p; exp->_p++; \r
166         return sqstd_rex_newnode(exp,t);\r
167 }\r
168 static SQInteger sqstd_rex_class(SQRex *exp)\r
169 {\r
170         SQInteger ret = -1;\r
171         SQInteger first = -1,chain;\r
172         if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\r
173                 ret = sqstd_rex_newnode(exp,OP_NCLASS);\r
174                 exp->_p++;\r
175         }else ret = sqstd_rex_newnode(exp,OP_CLASS);\r
176         \r
177         if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class"));\r
178         chain = ret;\r
179         while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
180                 if(*exp->_p == '-' && first != -1){ \r
181                         SQInteger r;\r
182                         if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));\r
183                         r = sqstd_rex_newnode(exp,OP_RANGE);\r
184                         if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));\r
185                         if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));\r
186                         exp->_nodes[r].left = exp->_nodes[first].type;\r
187                         SQInteger t = sqstd_rex_escapechar(exp);\r
188                         exp->_nodes[r].right = t;\r
189             exp->_nodes[chain].next = r;\r
190                         chain = r;\r
191                         first = -1;\r
192                 }\r
193                 else{\r
194                         if(first!=-1){\r
195                                 SQInteger c = first;\r
196                                 exp->_nodes[chain].next = c;\r
197                                 chain = c;\r
198                                 first = sqstd_rex_charnode(exp,SQTrue);\r
199                         }\r
200                         else{\r
201                                 first = sqstd_rex_charnode(exp,SQTrue);\r
202                         }\r
203                 }\r
204         }\r
205         if(first!=-1){\r
206                 SQInteger c = first;\r
207                 exp->_nodes[chain].next = c;\r
208                 chain = c;\r
209                 first = -1;\r
210         }\r
211         /* hack? */\r
212         exp->_nodes[ret].left = exp->_nodes[ret].next;\r
213         exp->_nodes[ret].next = -1;\r
214         return ret;\r
215 }\r
216 \r
217 static SQInteger sqstd_rex_parsenumber(SQRex *exp)\r
218 {\r
219         SQInteger ret = *exp->_p-'0';\r
220         SQInteger positions = 10;\r
221         exp->_p++;\r
222         while(isdigit(*exp->_p)) {\r
223                 ret = ret*10+(*exp->_p++-'0');\r
224                 if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));\r
225                 positions *= 10;\r
226         };\r
227         return ret;\r
228 }\r
229 \r
230 static SQInteger sqstd_rex_element(SQRex *exp)\r
231 {\r
232         SQInteger ret = -1;\r
233         switch(*exp->_p)\r
234         {\r
235         case '(': {\r
236                 SQInteger expr;\r
237                 exp->_p++;\r
238 \r
239 \r
240                 if(*exp->_p =='?') {\r
241                         exp->_p++;\r
242                         sqstd_rex_expect(exp,':');\r
243                         expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\r
244                 }\r
245                 else\r
246                         expr = sqstd_rex_newnode(exp,OP_EXPR);\r
247                 SQInteger newn = sqstd_rex_list(exp);\r
248                 exp->_nodes[expr].left = newn;\r
249                 ret = expr;\r
250                 sqstd_rex_expect(exp,')');\r
251                           }\r
252                           break;\r
253         case '[':\r
254                 exp->_p++;\r
255                 ret = sqstd_rex_class(exp);\r
256                 sqstd_rex_expect(exp,']');\r
257                 break;\r
258         case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\r
259         case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\r
260         default:\r
261                 ret = sqstd_rex_charnode(exp,SQFalse);\r
262                 break;\r
263         }\r
264 \r
265 \r
266         SQInteger op;\r
267         SQBool isgreedy = SQFalse;\r
268         unsigned short p0 = 0, p1 = 0;\r
269         switch(*exp->_p){\r
270                 case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\r
271                 case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\r
272                 case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break;\r
273                 case '{':\r
274                         exp->_p++;\r
275                         if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));\r
276                         p0 = (unsigned short)sqstd_rex_parsenumber(exp);\r
277                         /*******************************/\r
278                         switch(*exp->_p) {\r
279                 case '}':\r
280                         p1 = p0; exp->_p++;\r
281                         break;\r
282                 case ',':\r
283                         exp->_p++;\r
284                         p1 = 0xFFFF;\r
285                         if(isdigit(*exp->_p)){\r
286                                 p1 = (unsigned short)sqstd_rex_parsenumber(exp);\r
287                         }\r
288                         sqstd_rex_expect(exp,'}');\r
289                         break;\r
290                 default:\r
291                         sqstd_rex_error(exp,_SC(", or } expected"));\r
292                         }\r
293                         /*******************************/\r
294                         isgreedy = SQTrue; \r
295                         break;\r
296 \r
297         }\r
298         if(isgreedy) {\r
299                 SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\r
300                 op = OP_GREEDY;\r
301                 exp->_nodes[nnode].left = ret;\r
302                 exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
303                 ret = nnode;\r
304         }\r
305 \r
306         if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {\r
307                 SQInteger nnode = sqstd_rex_element(exp);\r
308                 exp->_nodes[ret].next = nnode;\r
309         }\r
310 \r
311         return ret;\r
312 }\r
313 \r
314 static SQInteger sqstd_rex_list(SQRex *exp)\r
315 {\r
316         SQInteger ret=-1,e;\r
317         if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\r
318                 exp->_p++;\r
319                 ret = sqstd_rex_newnode(exp,OP_BOL);\r
320         }\r
321         e = sqstd_rex_element(exp);\r
322         if(ret != -1) {\r
323                 exp->_nodes[ret].next = e;\r
324         }\r
325         else ret = e;\r
326 \r
327         if(*exp->_p == SQREX_SYMBOL_BRANCH) {\r
328                 SQInteger temp,tright;\r
329                 exp->_p++;\r
330                 temp = sqstd_rex_newnode(exp,OP_OR);\r
331                 exp->_nodes[temp].left = ret;\r
332                 tright = sqstd_rex_list(exp);\r
333                 exp->_nodes[temp].right = tright;\r
334                 ret = temp;\r
335         }\r
336         return ret;\r
337 }\r
338 \r
339 static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\r
340 {\r
341         switch(cclass) {\r
342         case 'a': return isalpha(c)?SQTrue:SQFalse;\r
343         case 'A': return !isalpha(c)?SQTrue:SQFalse;\r
344         case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\r
345         case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\r
346         case 's': return isspace(c)?SQTrue:SQFalse;\r
347         case 'S': return !isspace(c)?SQTrue:SQFalse;\r
348         case 'd': return isdigit(c)?SQTrue:SQFalse;\r
349         case 'D': return !isdigit(c)?SQTrue:SQFalse;\r
350         case 'x': return isxdigit(c)?SQTrue:SQFalse;\r
351         case 'X': return !isxdigit(c)?SQTrue:SQFalse;\r
352         case 'c': return iscntrl(c)?SQTrue:SQFalse;\r
353         case 'C': return !iscntrl(c)?SQTrue:SQFalse;\r
354         case 'p': return ispunct(c)?SQTrue:SQFalse;\r
355         case 'P': return !ispunct(c)?SQTrue:SQFalse;\r
356         case 'l': return islower(c)?SQTrue:SQFalse;\r
357         case 'u': return isupper(c)?SQTrue:SQFalse;\r
358         }\r
359         return SQFalse; /*cannot happen*/\r
360 }\r
361 \r
362 static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\r
363 {\r
364         do {\r
365                 switch(node->type) {\r
366                         case OP_RANGE:\r
367                                 if(c >= node->left && c <= node->right) return SQTrue;\r
368                                 break;\r
369                         case OP_CCLASS:\r
370                                 if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\r
371                                 break;\r
372                         default:\r
373                                 if(c == node->type)return SQTrue;\r
374                 }\r
375         } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
376         return SQFalse;\r
377 }\r
378 \r
379 static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)\r
380 {\r
381         \r
382         SQRexNodeType type = node->type;\r
383         switch(type) {\r
384         case OP_GREEDY: {\r
385                 //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\r
386                 SQRexNode *greedystop = NULL;\r
387                 SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
388                 const SQChar *s=str, *good = str;\r
389 \r
390                 if(node->next != -1) {\r
391                         greedystop = &exp->_nodes[node->next];\r
392                 }\r
393                 else {\r
394                         greedystop = next;\r
395                 }\r
396 \r
397                 while((nmaches == 0xFFFF || nmaches < p1)) {\r
398 \r
399                         const SQChar *stop;\r
400                         if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\r
401                                 break;\r
402                         nmaches++;\r
403                         good=s;\r
404                         if(greedystop) {\r
405                                 //checks that 0 matches satisfy the expression(if so skips)\r
406                                 //if not would always stop(for instance if is a '?')\r
407                                 if(greedystop->type != OP_GREEDY ||\r
408                                 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))\r
409                                 {\r
410                                         SQRexNode *gnext = NULL;\r
411                                         if(greedystop->next != -1) {\r
412                                                 gnext = &exp->_nodes[greedystop->next];\r
413                                         }else if(next && next->next != -1){\r
414                                                 gnext = &exp->_nodes[next->next];\r
415                                         }\r
416                                         stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);\r
417                                         if(stop) {\r
418                                                 //if satisfied stop it\r
419                                                 if(p0 == p1 && p0 == nmaches) break;\r
420                                                 else if(nmaches >= p0 && p1 == 0xFFFF) break;\r
421                                                 else if(nmaches >= p0 && nmaches <= p1) break;\r
422                                         }\r
423                                 }\r
424                         }\r
425                         \r
426                         if(s >= exp->_eol)\r
427                                 break;\r
428                 }\r
429                 if(p0 == p1 && p0 == nmaches) return good;\r
430                 else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
431                 else if(nmaches >= p0 && nmaches <= p1) return good;\r
432                 return NULL;\r
433         }\r
434         case OP_OR: {\r
435                         const SQChar *asd = str;\r
436                         SQRexNode *temp=&exp->_nodes[node->left];\r
437                         while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
438                                 if(temp->next != -1)\r
439                                         temp = &exp->_nodes[temp->next];\r
440                                 else\r
441                                         return asd;\r
442                         }\r
443                         asd = str;\r
444                         temp = &exp->_nodes[node->right];\r
445                         while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
446                                 if(temp->next != -1)\r
447                                         temp = &exp->_nodes[temp->next];\r
448                                 else\r
449                                         return asd;\r
450                         }\r
451                         return NULL;\r
452                         break;\r
453         }\r
454         case OP_EXPR:\r
455         case OP_NOCAPEXPR:{\r
456                         SQRexNode *n = &exp->_nodes[node->left];\r
457                         const SQChar *cur = str;\r
458                         SQInteger capture = -1;\r
459                         if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
460                                 capture = exp->_currsubexp;\r
461                                 exp->_matches[capture].begin = cur;\r
462                                 exp->_currsubexp++;\r
463                         }\r
464                         \r
465                         do {\r
466                                 SQRexNode *subnext = NULL;\r
467                                 if(n->next != -1) {\r
468                                         subnext = &exp->_nodes[n->next];\r
469                                 }else {\r
470                                         subnext = next;\r
471                                 }\r
472                                 if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {\r
473                                         if(capture != -1){\r
474                                                 exp->_matches[capture].begin = 0;\r
475                                                 exp->_matches[capture].len = 0;\r
476                                         }\r
477                                         return NULL;\r
478                                 }\r
479                         } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
480 \r
481                         if(capture != -1) \r
482                                 exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
483                         return cur;\r
484         }                                \r
485         case OP_WB:\r
486                 if(str == exp->_bol && !isspace(*str)\r
487                  || (str == exp->_eol && !isspace(*(str-1)))\r
488                  || (!isspace(*str) && isspace(*(str+1)))\r
489                  || (isspace(*str) && !isspace(*(str+1))) ) {\r
490                         return (node->left == 'b')?str:NULL;\r
491                 }\r
492                 return (node->left == 'b')?NULL:str;\r
493         case OP_BOL:\r
494                 if(str == exp->_bol) return str;\r
495                 return NULL;\r
496         case OP_EOL:\r
497                 if(str == exp->_eol) return str;\r
498                 return NULL;\r
499         case OP_DOT:{\r
500                 *str++;\r
501                                 }\r
502                 return str;\r
503         case OP_NCLASS:\r
504         case OP_CLASS:\r
505                 if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\r
506                         *str++;\r
507                         return str;\r
508                 }\r
509                 return NULL;\r
510         case OP_CCLASS:\r
511                 if(sqstd_rex_matchcclass(node->left,*str)) {\r
512                         *str++;\r
513                         return str;\r
514                 }\r
515                 return NULL;\r
516         default: /* char */\r
517                 if(*str != node->type) return NULL;\r
518                 *str++;\r
519                 return str;\r
520         }\r
521         return NULL;\r
522 }\r
523 \r
524 /* public api */\r
525 SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\r
526 {\r
527         SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));\r
528         exp->_eol = exp->_bol = NULL;\r
529         exp->_p = pattern;\r
530         exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\r
531         exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\r
532         exp->_nsize = 0;\r
533         exp->_matches = 0;\r
534         exp->_nsubexpr = 0;\r
535         exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\r
536         exp->_error = error;\r
537         exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\r
538         if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
539                 SQInteger res = sqstd_rex_list(exp);\r
540                 exp->_nodes[exp->_first].left = res;\r
541                 if(*exp->_p!='\0')\r
542                         sqstd_rex_error(exp,_SC("unexpected character"));\r
543 #ifdef _DEBUG\r
544                 {\r
545                         SQInteger nsize,i;\r
546                         SQRexNode *t;\r
547                         nsize = exp->_nsize;\r
548                         t = &exp->_nodes[0];\r
549                         scprintf(_SC("\n"));\r
550                         for(i = 0;i < nsize; i++) {\r
551                                 if(exp->_nodes[i].type>MAX_CHAR)\r
552                                         scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
553                                 else\r
554                                         scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
555                                 scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
556                         }\r
557                         scprintf(_SC("\n"));\r
558                 }\r
559 #endif\r
560                 exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\r
561                 memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\r
562         }\r
563         else{\r
564                 sqstd_rex_free(exp);\r
565                 return NULL;\r
566         }\r
567         return exp;\r
568 }\r
569 \r
570 void sqstd_rex_free(SQRex *exp)\r
571 {\r
572         if(exp) {\r
573                 if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\r
574                 if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\r
575                 if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\r
576                 sq_free(exp,sizeof(SQRex));\r
577         }\r
578 }\r
579 \r
580 SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\r
581 {\r
582         const SQChar* res = NULL;\r
583         exp->_bol = text;\r
584         exp->_eol = text + scstrlen(text);\r
585         exp->_currsubexp = 0;\r
586         res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);\r
587         if(res == NULL || res != exp->_eol)\r
588                 return SQFalse;\r
589         return SQTrue;\r
590 }\r
591 \r
592 SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\r
593 {\r
594         const SQChar *cur = NULL;\r
595         SQInteger node = exp->_first;\r
596         if(text_begin >= text_end) return SQFalse;\r
597         exp->_bol = text_begin;\r
598         exp->_eol = text_end;\r
599         do {\r
600                 cur = text_begin;\r
601                 while(node != -1) {\r
602                         exp->_currsubexp = 0;\r
603                         cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);\r
604                         if(!cur)\r
605                                 break;\r
606                         node = exp->_nodes[node].next;\r
607                 }\r
608                 *text_begin++;\r
609         } while(cur == NULL && text_begin != text_end);\r
610 \r
611         if(cur == NULL)\r
612                 return SQFalse;\r
613 \r
614         --text_begin;\r
615 \r
616         if(out_begin) *out_begin = text_begin;\r
617         if(out_end) *out_end = cur;\r
618         return SQTrue;\r
619 }\r
620 \r
621 SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\r
622 {\r
623         return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
624 }\r
625 \r
626 SQInteger sqstd_rex_getsubexpcount(SQRex* exp)\r
627 {\r
628         return exp->_nsubexpr;\r
629 }\r
630 \r
631 SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\r
632 {\r
633         if( n<0 || n >= exp->_nsubexpr) return SQFalse;\r
634         *subexp = exp->_matches[n];\r
635         return SQTrue;\r
636 }\r
637 \r