# sqstdrex.cpp

    00001 /* see copyright notice in squirrel.h */
    00002 #include <squirrel.h>
    00003 #include <string.h>
    00004 #include <ctype.h>
    00005 #include <exception>
    00006 #include "sqstdstring.h"
    00007
    00008 #ifdef _UNICODE
    00009 #define scisprint iswprint
    00010 #else
    00011 #define scisprint isprint
    00012 #endif
    00013
    00014 #ifdef _DEBUG
    00015 #include <stdio.h>
    00016
    00017 static const SQChar *g_nnames[] =
    00018 {
    00019   _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
    00020   _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
    00021   _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
    00022   _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
    00023 };
    00024
    00025 #endif
    00026
    00027 #define OP_GREEDY   (MAX_CHAR+1) // * + ? {n}
    00028 #define OP_OR     (MAX_CHAR+2)
    00029 #define OP_EXPR     (MAX_CHAR+3) //parentesis ()
    00030 #define OP_NOCAPEXPR  (MAX_CHAR+4) //parentesis (?:)
    00031 #define OP_DOT      (MAX_CHAR+5)
    00032 #define OP_CLASS    (MAX_CHAR+6)
    00033 #define OP_CCLASS   (MAX_CHAR+7)
    00034 #define OP_NCLASS   (MAX_CHAR+8) //negates class the [^
    00035 #define OP_RANGE    (MAX_CHAR+9)
    00036 #define OP_CHAR     (MAX_CHAR+10)
    00037 #define OP_EOL      (MAX_CHAR+11)
    00038 #define OP_BOL      (MAX_CHAR+12)
    00039 #define OP_WB     (MAX_CHAR+13)
    00040
    00041 #define SQREX_SYMBOL_ANY_CHAR ('.')
    00042 #define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
    00043 #define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
    00044 #define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
    00045 #define SQREX_SYMBOL_BRANCH ('|')
    00046 #define SQREX_SYMBOL_END_OF_STRING ('$')
    00047 #define SQREX_SYMBOL_BEGINNING_OF_STRING ('^')
    00048 #define SQREX_SYMBOL_ESCAPE_CHAR ('\\')
    00049
    00050
    00051 typedef int SQRexNodeType;
    00052
    00053 typedef struct tagSQRexNode{
    00054   SQRexNodeType type;
    00055   SQInteger left;
    00056   SQInteger right;
    00057   SQInteger next;
    00058 }SQRexNode;
    00059
    00060 struct SQRex{
    00061   const SQChar *_eol;
    00062   const SQChar *_bol;
    00063   const SQChar *_p;
    00064   SQInteger _first;
    00065   SQInteger _op;
    00066   SQRexNode *_nodes;
    00067   SQInteger _nallocated;
    00068   SQInteger _nsize;
    00069   SQInteger _nsubexpr;
    00070   SQRexMatch *_matches;
    00071   SQInteger _currsubexp;
    00072   const SQChar **_error;
    00073 };
    00074
    00075 static SQInteger sqstd_rex_list(SQRex *exp);
    00076
    00077 static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)
    00078 {
    00079   SQRexNode n;
    00080   n.type = type;
    00081   n.next = n.right = n.left = -1;
    00082   if(type == OP_EXPR)
    00083     n.right = exp->_nsubexpr++;
    00084   if(exp->_nallocated < (exp->_nsize + 1)) {
    00085     SQInteger oldsize = exp->_nallocated;
    00086     exp->_nallocated *= 2;
    00087     exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));
    00088   }
    00089   exp->_nodes[exp->_nsize++] = n;
    00090   SQInteger newid = exp->_nsize - 1;
    00091   return (SQInteger)newid;
    00092 }
    00093
    00094 static void sqstd_rex_error(SQRex *exp,const SQChar *error)
    00095 {
    00096   if(exp->_error) *exp->_error = error;
    00097   throw std::exception();
    00098 }
    00099
    00100 static void sqstd_rex_expect(SQRex *exp, SQChar n){
    00101   if((*exp->_p) != n)
    00102     sqstd_rex_error(exp, _SC("expected paren"));
    00103   exp->_p++;
    00104 }
    00105
    00106 static SQChar sqstd_rex_escapechar(SQRex *exp)
    00107 {
    00108   if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){
    00109     exp->_p++;
    00110     switch(*exp->_p) {
    00111     case 'v': exp->_p++; return '\v';
    00112     case 'n': exp->_p++; return '\n';
    00113     case 't': exp->_p++; return '\t';
    00114     case 'r': exp->_p++; return '\r';
    00115     case 'f': exp->_p++; return '\f';
    00116     default: return (*exp->_p++);
    00117     }
    00118   } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));
    00119   return (*exp->_p++);
    00120 }
    00121
    00122 static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)
    00123 {
    00124   SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);
    00125   exp->_nodes[n].left = classid;
    00126   return n;
    00127 }
    00128
    00129 static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)
    00130 {
    00131   SQChar t;
    00132   if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {
    00133     exp->_p++;
    00134     switch(*exp->_p) {
    00135       case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');
    00136       case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');
    00137       case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');
    00138       case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');
    00139       case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');
    00140       case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
    00141       case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
    00142       case 'p': case 'P': case 'l': case 'u':
    00143         {
    00144         t = *exp->_p; exp->_p++;
    00145         return sqstd_rex_charclass(exp,t);
    00146         }
    00147       case 'b':
    00148       case 'B':
    00149         if(!isclass) {
    00150           SQInteger node = sqstd_rex_newnode(exp,OP_WB);
    00151           exp->_nodes[node].left = *exp->_p;
    00152           exp->_p++;
    00153           return node;
    00154         } //else default
    00155       default:
    00156         t = *exp->_p; exp->_p++;
    00157         return sqstd_rex_newnode(exp,t);
    00158     }
    00159   }
    00160   else if(!scisprint(*exp->_p)) {
    00161
    00162     sqstd_rex_error(exp,_SC("letter expected"));
    00163   }
    00164   t = *exp->_p; exp->_p++;
    00165   return sqstd_rex_newnode(exp,t);
    00166 }
    00167 static SQInteger sqstd_rex_class(SQRex *exp)
    00168 {
    00169   SQInteger ret = -1;
    00170   SQInteger first = -1,chain;
    00171   if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){
    00172     ret = sqstd_rex_newnode(exp,OP_NCLASS);
    00173     exp->_p++;
    00174   }else ret = sqstd_rex_newnode(exp,OP_CLASS);
    00175
    00176   if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class"));
    00177   chain = ret;
    00178   while(*exp->_p != ']' && exp->_p != exp->_eol) {
    00179     if(*exp->_p == '-' && first != -1){
    00180       SQInteger r;
    00181       if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));
    00182       r = sqstd_rex_newnode(exp,OP_RANGE);
    00183       if((SQChar)first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));
    00184       if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));
    00185       exp->_nodes[r].left = exp->_nodes[first].type;
    00186       SQInteger t = sqstd_rex_escapechar(exp);
    00187       exp->_nodes[r].right = t;
    00188             exp->_nodes[chain].next = r;
    00189       chain = r;
    00190       first = -1;
    00191     }
    00192     else{
    00193       if(first!=-1){
    00194         SQInteger c = first;
    00195         exp->_nodes[chain].next = c;
    00196         chain = c;
    00197         first = sqstd_rex_charnode(exp,SQTrue);
    00198       }
    00199       else{
    00200         first = sqstd_rex_charnode(exp,SQTrue);
    00201       }
    00202     }
    00203   }
    00204   if(first!=-1){
    00205     SQInteger c = first;
    00206     exp->_nodes[chain].next = c;
    00207     chain = c;
    00208     first = -1;
    00209   }
    00210   /* hack? */
    00211   exp->_nodes[ret].left = exp->_nodes[ret].next;
    00212   exp->_nodes[ret].next = -1;
    00213   return ret;
    00214 }
    00215
    00216 static SQInteger sqstd_rex_parsenumber(SQRex *exp)
    00217 {
    00218   SQInteger ret = *exp->_p-'0';
    00219   SQInteger positions = 10;
    00220   exp->_p++;
    00221   while(isdigit(*exp->_p)) {
    00222     ret = ret*10+(*exp->_p++-'0');
    00223     if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));
    00224     positions *= 10;
    00225   };
    00226   return ret;
    00227 }
    00228
    00229 static SQInteger sqstd_rex_element(SQRex *exp)
    00230 {
    00231   SQInteger ret = -1;
    00232   switch(*exp->_p)
    00233   {
    00234   case '(': {
    00235     SQInteger expr;
    00236     exp->_p++;
    00237
    00238
    00239     if(*exp->_p =='?') {
    00240       exp->_p++;
    00241       sqstd_rex_expect(exp,_SC(':'));
    00242       expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);
    00243     }
    00244     else
    00245       expr = sqstd_rex_newnode(exp,OP_EXPR);
    00246     SQInteger newn = sqstd_rex_list(exp);
    00247     exp->_nodes[expr].left = newn;
    00248     ret = expr;
    00249     sqstd_rex_expect(exp,_SC(')'));
    00250         }
    00251         break;
    00252   case '[':
    00253     exp->_p++;
    00254     ret = sqstd_rex_class(exp);
    00255     sqstd_rex_expect(exp,_SC(']'));
    00256     break;
    00257   case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;
    00258   case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;
    00259   default:
    00260     ret = sqstd_rex_charnode(exp,SQFalse);
    00261     break;
    00262   }
    00263
    00264
    00265   SQInteger op;
    00266   SQBool isgreedy = SQFalse;
    00267   unsigned short p0 = 0, p1 = 0;
    00268   switch(*exp->_p){
    00269     case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;
    00270     case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;
    00271     case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break;
    00272     case '{':
    00273       exp->_p++;
    00274       if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));
    00275       p0 = (unsigned short)sqstd_rex_parsenumber(exp);
    00276       /*******************************/
    00277       switch(*exp->_p) {
    00278     case '}':
    00279       p1 = p0; exp->_p++;
    00280       break;
    00281     case ',':
    00282       exp->_p++;
    00283       p1 = 0xFFFF;
    00284       if(isdigit(*exp->_p)){
    00285         p1 = (unsigned short)sqstd_rex_parsenumber(exp);
    00286       }
    00287       sqstd_rex_expect(exp,_SC('}'));
    00288       break;
    00289     default:
    00290       sqstd_rex_error(exp,_SC(", or } expected"));
    00291       }
    00292       /*******************************/
    00293       isgreedy = SQTrue;
    00294       break;
    00295
    00296   }
    00297   if(isgreedy) {
    00298     SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);
    00299     op = OP_GREEDY;
    00300     exp->_nodes[nnode].left = ret;
    00301     exp->_nodes[nnode].right = ((p0)<<16)|p1;
    00302     ret = nnode;
    00303   }
    00304
    00305   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')) {
    00306     SQInteger nnode = sqstd_rex_element(exp);
    00307     exp->_nodes[ret].next = nnode;
    00308   }
    00309
    00310   return ret;
    00311 }
    00312
    00313 static SQInteger sqstd_rex_list(SQRex *exp)
    00314 {
    00315   SQInteger ret=-1,e;
    00316   if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {
    00317     exp->_p++;
    00318     ret = sqstd_rex_newnode(exp,OP_BOL);
    00319   }
    00320   e = sqstd_rex_element(exp);
    00321   if(ret != -1) {
    00322     exp->_nodes[ret].next = e;
    00323   }
    00324   else ret = e;
    00325
    00326   if(*exp->_p == SQREX_SYMBOL_BRANCH) {
    00327     SQInteger temp,tright;
    00328     exp->_p++;
    00329     temp = sqstd_rex_newnode(exp,OP_OR);
    00330     exp->_nodes[temp].left = ret;
    00331     tright = sqstd_rex_list(exp);
    00332     exp->_nodes[temp].right = tright;
    00333     ret = temp;
    00334   }
    00335   return ret;
    00336 }
    00337
    00338 static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)
    00339 {
    00340   switch(cclass) {
    00341   case 'a': return isalpha(c)?SQTrue:SQFalse;
    00342   case 'A': return !isalpha(c)?SQTrue:SQFalse;
    00343   case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;
    00344   case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;
    00345   case 's': return isspace(c)?SQTrue:SQFalse;
    00346   case 'S': return !isspace(c)?SQTrue:SQFalse;
    00347   case 'd': return isdigit(c)?SQTrue:SQFalse;
    00348   case 'D': return !isdigit(c)?SQTrue:SQFalse;
    00349   case 'x': return isxdigit(c)?SQTrue:SQFalse;
    00350   case 'X': return !isxdigit(c)?SQTrue:SQFalse;
    00351   case 'c': return iscntrl(c)?SQTrue:SQFalse;
    00352   case 'C': return !iscntrl(c)?SQTrue:SQFalse;
    00353   case 'p': return ispunct(c)?SQTrue:SQFalse;
    00354   case 'P': return !ispunct(c)?SQTrue:SQFalse;
    00355   case 'l': return islower(c)?SQTrue:SQFalse;
    00356   case 'u': return isupper(c)?SQTrue:SQFalse;
    00357   }
    00358   return SQFalse; /*cannot happen*/
    00359 }
    00360
    00361 static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQInteger c)
    00362 {
    00363   do {
    00364     switch(node->type) {
    00365       case OP_RANGE:
    00366         if(c >= node->left && c <= node->right) return SQTrue;
    00367         break;
    00368       case OP_CCLASS:
    00369         if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;
    00370         break;
    00371       default:
    00372         if(c == node->type)return SQTrue;
    00373     }
    00374   } while((node->next != -1) && (node = &exp->_nodes[node->next]));
    00375   return SQFalse;
    00376 }
    00377
    00378 static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)
    00379 {
    00380
    00381   SQRexNodeType type = node->type;
    00382   switch(type) {
    00383   case OP_GREEDY: {
    00384     //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
    00385     SQRexNode *greedystop = NULL;
    00386     SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
    00387     const SQChar *s=str, *good = str;
    00388
    00389     if(node->next != -1) {
    00390       greedystop = &exp->_nodes[node->next];
    00391     }
    00392     else {
    00393       greedystop = next;
    00394     }
    00395
    00396     while((nmaches == 0xFFFF || nmaches < p1)) {
    00397
    00398       const SQChar *stop;
    00399       if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
    00400         break;
    00401       nmaches++;
    00402       good=s;
    00403       if(greedystop) {
    00404         //checks that 0 matches satisfy the expression(if so skips)
    00405         //if not would always stop(for instance if is a '?')
    00406         if(greedystop->type != OP_GREEDY ||
    00407         (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
    00408         {
    00409           SQRexNode *gnext = NULL;
    00410           if(greedystop->next != -1) {
    00411             gnext = &exp->_nodes[greedystop->next];
    00412           }else if(next && next->next != -1){
    00413             gnext = &exp->_nodes[next->next];
    00414           }
    00415           stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);
    00416           if(stop) {
    00417             //if satisfied stop it
    00418             if(p0 == p1 && p0 == nmaches) break;
    00419             else if(nmaches >= p0 && p1 == 0xFFFF) break;
    00420             else if(nmaches >= p0 && nmaches <= p1) break;
    00421           }
    00422         }
    00423       }
    00424
    00425       if(s >= exp->_eol)
    00426         break;
    00427     }
    00428     if(p0 == p1 && p0 == nmaches) return good;
    00429     else if(nmaches >= p0 && p1 == 0xFFFF) return good;
    00430     else if(nmaches >= p0 && nmaches <= p1) return good;
    00431     return NULL;
    00432   }
    00433   case OP_OR: {
    00434       const SQChar *asd = str;
    00435       SQRexNode *temp=&exp->_nodes[node->left];
    00436       while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {
    00437         if(temp->next != -1)
    00438           temp = &exp->_nodes[temp->next];
    00439         else
    00440           return asd;
    00441       }
    00442       asd = str;
    00443       temp = &exp->_nodes[node->right];
    00444       while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {
    00445         if(temp->next != -1)
    00446           temp = &exp->_nodes[temp->next];
    00447         else
    00448           return asd;
    00449       }
    00450       return NULL;
    00451       break;
    00452   }
    00453   case OP_EXPR:
    00454   case OP_NOCAPEXPR:{
    00455       SQRexNode *n = &exp->_nodes[node->left];
    00456       const SQChar *cur = str;
    00457       SQInteger capture = -1;
    00458       if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
    00459         capture = exp->_currsubexp;
    00460         exp->_matches[capture].begin = cur;
    00461         exp->_currsubexp++;
    00462       }
    00463
    00464       do {
    00465         SQRexNode *subnext = NULL;
    00466         if(n->next != -1) {
    00467           subnext = &exp->_nodes[n->next];
    00468         }else {
    00469           subnext = next;
    00470         }
    00471         if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {
    00472           if(capture != -1){
    00473             exp->_matches[capture].begin = 0;
    00474             exp->_matches[capture].len = 0;
    00475           }
    00476           return NULL;
    00477         }
    00478       } while((n->next != -1) && (n = &exp->_nodes[n->next]));
    00479
    00480       if(capture != -1)
    00481         exp->_matches[capture].len = cur - exp->_matches[capture].begin;
    00482       return cur;
    00483   }
    00484   case OP_WB:
    00485     if((str == exp->_bol && !isspace(*str))
    00486      || (str == exp->_eol && !isspace(*(str-1)))
    00487      || (!isspace(*str) && isspace(*(str+1)))
    00488      || (isspace(*str) && !isspace(*(str+1))) ) {
    00489       return (node->left == 'b')?str:NULL;
    00490     }
    00491     return (node->left == 'b')?NULL:str;
    00492   case OP_BOL:
    00493     if(str == exp->_bol) return str;
    00494     return NULL;
    00495   case OP_EOL:
    00496     if(str == exp->_eol) return str;
    00497     return NULL;
    00498   case OP_DOT:{
    00499     *str++;
    00500         }
    00501     return str;
    00502   case OP_NCLASS:
    00503   case OP_CLASS:
    00504     if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {
    00505       *str++;
    00506       return str;
    00507     }
    00508     return NULL;
    00509   case OP_CCLASS:
    00510     if(sqstd_rex_matchcclass(node->left,*str)) {
    00511       *str++;
    00512       return str;
    00513     }
    00514     return NULL;
    00515   default: /* char */
    00516     if(*str != (SQChar)node->type) return NULL;
    00517     *str++;
    00518     return str;
    00519   }
    00520   return NULL;
    00521 }
    00522
    00523 /* public api */
    00524 SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)
    00525 {
    00526   SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));
    00527   exp->_eol = exp->_bol = NULL;
    00528   exp->_p = pattern;
    00529   exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);
    00530   exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));
    00531   exp->_nsize = 0;
    00532   exp->_matches = 0;
    00533   exp->_nsubexpr = 0;
    00534   exp->_first = sqstd_rex_newnode(exp,OP_EXPR);
    00535   exp->_error = error;
    00536   try {
    00537     SQInteger res = sqstd_rex_list(exp);
    00538     exp->_nodes[exp->_first].left = res;
    00539     if(*exp->_p!='\0')
    00540       sqstd_rex_error(exp,_SC("unexpected character"));
    00541 #ifdef _DEBUG
    00542     {
    00543       SQInteger nsize,i;
    00544       SQRexNode *t;
    00545       nsize = exp->_nsize;
    00546       t = &exp->_nodes[0];
    00547       scprintf(_SC("\n"));
    00548       /* XXX -- The (int) casts are needed to silent warnings on 64bit systems (SQInteger is 64bit, %d assumes 32bit, (int) is 32bit) */
    00549       for(i = 0;i < nsize; i++) {
    00550         if(exp->_nodes[i].type>MAX_CHAR)
    00551           scprintf(_SC("[%02d] %10s "),(int)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
    00552         else
    00553           scprintf(_SC("[%02d] %10c "),(int)i,exp->_nodes[i].type);
    00554         scprintf(_SC("left %02d right %02d next %02d\n"),(int)exp->_nodes[i].left,(int)exp->_nodes[i].right,(int)exp->_nodes[i].next);
    00555       }
    00556       scprintf(_SC("\n"));
    00557     }
    00558 #endif
    00559     exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));
    00560     memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));
    00561     return exp;
    00562   }
    00563   catch (...) {
    00564     sqstd_rex_free(exp);
    00565     return NULL;
    00566   }
    00567 }
    00568
    00569 void sqstd_rex_free(SQRex *exp)
    00570 {
    00571   if(exp) {
    00572     if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));
    00573     if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));
    00574     sq_free(exp,sizeof(SQRex));
    00575   }
    00576 }
    00577
    00578 SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)
    00579 {
    00580   const SQChar* res = NULL;
    00581   exp->_bol = text;
    00582   exp->_eol = text + scstrlen(text);
    00583   exp->_currsubexp = 0;
    00584   res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);
    00585   if(res == NULL || res != exp->_eol)
    00586     return SQFalse;
    00587   return SQTrue;
    00588 }
    00589
    00590 SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)
    00591 {
    00592   const SQChar *cur = NULL;
    00593   SQInteger node = exp->_first;
    00594   if(text_begin >= text_end) return SQFalse;
    00595   exp->_bol = text_begin;
    00596   exp->_eol = text_end;
    00597   do {
    00598     cur = text_begin;
    00599     while(node != -1) {
    00600       exp->_currsubexp = 0;
    00601       cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);
    00602       if(!cur)
    00603         break;
    00604       node = exp->_nodes[node].next;
    00605     }
    00606     *text_begin++;
    00607   } while(cur == NULL && text_begin != text_end);
    00608
    00609   if(cur == NULL)
    00610     return SQFalse;
    00611
    00612   --text_begin;
    00613
    00614   if(out_begin) *out_begin = text_begin;
    00615   if(out_end) *out_end = cur;
    00616   return SQTrue;
    00617 }
    00618
    00619 SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)
    00620 {
    00621   return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
    00622 }
    00623
    00624 SQInteger sqstd_rex_getsubexpcount(SQRex* exp)
    00625 {
    00626   return exp->_nsubexpr;
    00627 }
    00628
    00629 SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)
    00630 {
    00631   if( n<0 || n >= exp->_nsubexpr) return SQFalse;
    00632   *subexp = exp->_matches[n];
    00633   return SQTrue;
    00634 }
    00635