123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- /*
- ** 2012-11-13
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- ******************************************************************************
- **
- ** The code in this file implements a compact but reasonably
- ** efficient regular-expression matcher for posix extended regular
- ** expressions against UTF8 text.
- **
- ** This file is an SQLite extension. It registers a single function
- ** named "regexp(A,B)" where A is the regular expression and B is the
- ** string to be matched. By registering this function, SQLite will also
- ** then implement the "B regexp A" operator. Note that with the function
- ** the regular expression comes first, but with the operator it comes
- ** second.
- **
- ** The following regular expression syntax is supported:
- **
- ** X* zero or more occurrences of X
- ** X+ one or more occurrences of X
- ** X? zero or one occurrences of X
- ** X{p,q} between p and q occurrences of X
- ** (X) match X
- ** X|Y X or Y
- ** ^X X occurring at the beginning of the string
- ** X$ X occurring at the end of the string
- ** . Match any single character
- ** \c Character c where c is one of \{}()[]|*+?.
- ** \c C-language escapes for c in afnrtv. ex: \t or \n
- ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
- ** \xXX Where XX is exactly 2 hex digits, unicode value XX
- ** [abc] Any single character from the set abc
- ** [^abc] Any single character not in the set abc
- ** [a-z] Any single character in the range a-z
- ** [^a-z] Any single character not in the range a-z
- ** \b Word boundary
- ** \w Word character. [A-Za-z0-9_]
- ** \W Non-word character
- ** \d Digit
- ** \D Non-digit
- ** \s Whitespace character
- ** \S Non-whitespace character
- **
- ** A nondeterministic finite automaton (NFA) is used for matching, so the
- ** performance is bounded by O(N*M) where N is the size of the regular
- ** expression and M is the size of the input string. The matcher never
- ** exhibits exponential behavior. Note that the X{p,q} operator expands
- ** to p copies of X following by q-p copies of X? and that the size of the
- ** regular expression in the O(N*M) performance bound is computed after
- ** this expansion.
- */
- #include <string.h>
- #include <stdlib.h>
- #include "sqlite3ext.h"
- SQLITE_EXTENSION_INIT1
- /*
- ** The following #defines change the names of some functions implemented in
- ** this file to prevent name collisions with C-library functions of the
- ** same name.
- */
- #define re_match sqlite3re_match
- #define re_compile sqlite3re_compile
- #define re_free sqlite3re_free
- /* The end-of-input character */
- #define RE_EOF 0 /* End of input */
- /* The NFA is implemented as sequence of opcodes taken from the following
- ** set. Each opcode has a single integer argument.
- */
- #define RE_OP_MATCH 1 /* Match the one character in the argument */
- #define RE_OP_ANY 2 /* Match any one character. (Implements ".") */
- #define RE_OP_ANYSTAR 3 /* Special optimized version of .* */
- #define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */
- #define RE_OP_GOTO 5 /* Jump to opcode at iArg */
- #define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */
- #define RE_OP_CC_INC 7 /* Beginning of a [...] character class */
- #define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */
- #define RE_OP_CC_VALUE 9 /* Single value in a character class */
- #define RE_OP_CC_RANGE 10 /* Range of values in a character class */
- #define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */
- #define RE_OP_NOTWORD 12 /* Not a perl word character */
- #define RE_OP_DIGIT 13 /* digit: [0-9] */
- #define RE_OP_NOTDIGIT 14 /* Not a digit */
- #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
- #define RE_OP_NOTSPACE 16 /* Not a digit */
- #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
- /* Each opcode is a "state" in the NFA */
- typedef unsigned short ReStateNumber;
- /* Because this is an NFA and not a DFA, multiple states can be active at
- ** once. An instance of the following object records all active states in
- ** the NFA. The implementation is optimized for the common case where the
- ** number of actives states is small.
- */
- typedef struct ReStateSet {
- unsigned nState; /* Number of current states */
- ReStateNumber *aState; /* Current states */
- } ReStateSet;
- /* An input string read one character at a time.
- */
- typedef struct ReInput ReInput;
- struct ReInput {
- const unsigned char *z; /* All text */
- int i; /* Next byte to read */
- int mx; /* EOF when i>=mx */
- };
- /* A compiled NFA (or an NFA that is in the process of being compiled) is
- ** an instance of the following object.
- */
- typedef struct ReCompiled ReCompiled;
- struct ReCompiled {
- ReInput sIn; /* Regular expression text */
- const char *zErr; /* Error message to return */
- char *aOp; /* Operators for the virtual machine */
- int *aArg; /* Arguments to each operator */
- unsigned (*xNextChar)(ReInput*); /* Next character function */
- unsigned char zInit[12]; /* Initial text to match */
- int nInit; /* Number of characters in zInit */
- unsigned nState; /* Number of entries in aOp[] and aArg[] */
- unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
- };
- /* Add a state to the given state set if it is not already there */
- static void re_add_state(ReStateSet *pSet, int newState){
- unsigned i;
- for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
- pSet->aState[pSet->nState++] = newState;
- }
- /* Extract the next unicode character from *pzIn and return it. Advance
- ** *pzIn to the first byte past the end of the character returned. To
- ** be clear: this routine converts utf8 to unicode. This routine is
- ** optimized for the common case where the next character is a single byte.
- */
- static unsigned re_next_char(ReInput *p){
- unsigned c;
- if( p->i>=p->mx ) return 0;
- c = p->z[p->i++];
- if( c>=0x80 ){
- if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
- c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
- if( c<0x80 ) c = 0xfffd;
- }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
- && (p->z[p->i+1]&0xc0)==0x80 ){
- c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
- p->i += 2;
- if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
- }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
- && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
- c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
- | (p->z[p->i+2]&0x3f);
- p->i += 3;
- if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
- }else{
- c = 0xfffd;
- }
- }
- return c;
- }
- static unsigned re_next_char_nocase(ReInput *p){
- unsigned c = re_next_char(p);
- if( c>='A' && c<='Z' ) c += 'a' - 'A';
- return c;
- }
- /* Return true if c is a perl "word" character: [A-Za-z0-9_] */
- static int re_word_char(int c){
- return (c>='0' && c<='9') || (c>='a' && c<='z')
- || (c>='A' && c<='Z') || c=='_';
- }
- /* Return true if c is a "digit" character: [0-9] */
- static int re_digit_char(int c){
- return (c>='0' && c<='9');
- }
- /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
- static int re_space_char(int c){
- return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
- }
- /* Run a compiled regular expression on the zero-terminated input
- ** string zIn[]. Return true on a match and false if there is no match.
- */
- static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
- ReStateSet aStateSet[2], *pThis, *pNext;
- ReStateNumber aSpace[100];
- ReStateNumber *pToFree;
- unsigned int i = 0;
- unsigned int iSwap = 0;
- int c = RE_EOF+1;
- int cPrev = 0;
- int rc = 0;
- ReInput in;
- in.z = zIn;
- in.i = 0;
- in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn);
- /* Look for the initial prefix match, if there is one. */
- if( pRe->nInit ){
- unsigned char x = pRe->zInit[0];
- while( in.i+pRe->nInit<=in.mx
- && (zIn[in.i]!=x ||
- strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
- ){
- in.i++;
- }
- if( in.i+pRe->nInit>in.mx ) return 0;
- }
- if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
- pToFree = 0;
- aStateSet[0].aState = aSpace;
- }else{
- pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState );
- if( pToFree==0 ) return -1;
- aStateSet[0].aState = pToFree;
- }
- aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
- pNext = &aStateSet[1];
- pNext->nState = 0;
- re_add_state(pNext, 0);
- while( c!=RE_EOF && pNext->nState>0 ){
- cPrev = c;
- c = pRe->xNextChar(&in);
- pThis = pNext;
- pNext = &aStateSet[iSwap];
- iSwap = 1 - iSwap;
- pNext->nState = 0;
- for(i=0; i<pThis->nState; i++){
- int x = pThis->aState[i];
- switch( pRe->aOp[x] ){
- case RE_OP_MATCH: {
- if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_ANY: {
- re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_WORD: {
- if( re_word_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_NOTWORD: {
- if( !re_word_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_DIGIT: {
- if( re_digit_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_NOTDIGIT: {
- if( !re_digit_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_SPACE: {
- if( re_space_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_NOTSPACE: {
- if( !re_space_char(c) ) re_add_state(pNext, x+1);
- break;
- }
- case RE_OP_BOUNDARY: {
- if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1);
- break;
- }
- case RE_OP_ANYSTAR: {
- re_add_state(pNext, x);
- re_add_state(pThis, x+1);
- break;
- }
- case RE_OP_FORK: {
- re_add_state(pThis, x+pRe->aArg[x]);
- re_add_state(pThis, x+1);
- break;
- }
- case RE_OP_GOTO: {
- re_add_state(pThis, x+pRe->aArg[x]);
- break;
- }
- case RE_OP_ACCEPT: {
- rc = 1;
- goto re_match_end;
- }
- case RE_OP_CC_INC:
- case RE_OP_CC_EXC: {
- int j = 1;
- int n = pRe->aArg[x];
- int hit = 0;
- for(j=1; j>0 && j<n; j++){
- if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
- if( pRe->aArg[x+j]==c ){
- hit = 1;
- j = -1;
- }
- }else{
- if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){
- hit = 1;
- j = -1;
- }else{
- j++;
- }
- }
- }
- if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
- if( hit ) re_add_state(pNext, x+n);
- break;
- }
- }
- }
- }
- for(i=0; i<pNext->nState; i++){
- if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
- }
- re_match_end:
- sqlite3_free(pToFree);
- return rc;
- }
- /* Resize the opcode and argument arrays for an RE under construction.
- */
- static int re_resize(ReCompiled *p, int N){
- char *aOp;
- int *aArg;
- aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0]));
- if( aOp==0 ) return 1;
- p->aOp = aOp;
- aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0]));
- if( aArg==0 ) return 1;
- p->aArg = aArg;
- p->nAlloc = N;
- return 0;
- }
- /* Insert a new opcode and argument into an RE under construction. The
- ** insertion point is just prior to existing opcode iBefore.
- */
- static int re_insert(ReCompiled *p, int iBefore, int op, int arg){
- int i;
- if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0;
- for(i=p->nState; i>iBefore; i--){
- p->aOp[i] = p->aOp[i-1];
- p->aArg[i] = p->aArg[i-1];
- }
- p->nState++;
- p->aOp[iBefore] = op;
- p->aArg[iBefore] = arg;
- return iBefore;
- }
- /* Append a new opcode and argument to the end of the RE under construction.
- */
- static int re_append(ReCompiled *p, int op, int arg){
- return re_insert(p, p->nState, op, arg);
- }
- /* Make a copy of N opcodes starting at iStart onto the end of the RE
- ** under construction.
- */
- static void re_copy(ReCompiled *p, int iStart, int N){
- if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
- memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
- memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
- p->nState += N;
- }
- /* Return true if c is a hexadecimal digit character: [0-9a-fA-F]
- ** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If
- ** c is not a hex digit *pV is unchanged.
- */
- static int re_hex(int c, int *pV){
- if( c>='0' && c<='9' ){
- c -= '0';
- }else if( c>='a' && c<='f' ){
- c -= 'a' - 10;
- }else if( c>='A' && c<='F' ){
- c -= 'A' - 10;
- }else{
- return 0;
- }
- *pV = (*pV)*16 + (c & 0xff);
- return 1;
- }
- /* A backslash character has been seen, read the next character and
- ** return its interpretation.
- */
- static unsigned re_esc_char(ReCompiled *p){
- static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
- static const char zTrans[] = "\a\f\n\r\t\v";
- int i, v = 0;
- char c;
- if( p->sIn.i>=p->sIn.mx ) return 0;
- c = p->sIn.z[p->sIn.i];
- if( c=='u' && p->sIn.i+4<p->sIn.mx ){
- const unsigned char *zIn = p->sIn.z + p->sIn.i;
- if( re_hex(zIn[1],&v)
- && re_hex(zIn[2],&v)
- && re_hex(zIn[3],&v)
- && re_hex(zIn[4],&v)
- ){
- p->sIn.i += 5;
- return v;
- }
- }
- if( c=='x' && p->sIn.i+2<p->sIn.mx ){
- const unsigned char *zIn = p->sIn.z + p->sIn.i;
- if( re_hex(zIn[1],&v)
- && re_hex(zIn[2],&v)
- ){
- p->sIn.i += 3;
- return v;
- }
- }
- for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
- if( zEsc[i] ){
- if( i<6 ) c = zTrans[i];
- p->sIn.i++;
- }else{
- p->zErr = "unknown \\ escape";
- }
- return c;
- }
- /* Forward declaration */
- static const char *re_subcompile_string(ReCompiled*);
- /* Peek at the next byte of input */
- static unsigned char rePeek(ReCompiled *p){
- return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
- }
- /* Compile RE text into a sequence of opcodes. Continue up to the
- ** first unmatched ")" character, then return. If an error is found,
- ** return a pointer to the error message string.
- */
- static const char *re_subcompile_re(ReCompiled *p){
- const char *zErr;
- int iStart, iEnd, iGoto;
- iStart = p->nState;
- zErr = re_subcompile_string(p);
- if( zErr ) return zErr;
- while( rePeek(p)=='|' ){
- iEnd = p->nState;
- re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
- iGoto = re_append(p, RE_OP_GOTO, 0);
- p->sIn.i++;
- zErr = re_subcompile_string(p);
- if( zErr ) return zErr;
- p->aArg[iGoto] = p->nState - iGoto;
- }
- return 0;
- }
- /* Compile an element of regular expression text (anything that can be
- ** an operand to the "|" operator). Return NULL on success or a pointer
- ** to the error message if there is a problem.
- */
- static const char *re_subcompile_string(ReCompiled *p){
- int iPrev = -1;
- int iStart;
- unsigned c;
- const char *zErr;
- while( (c = p->xNextChar(&p->sIn))!=0 ){
- iStart = p->nState;
- switch( c ){
- case '|':
- case '$':
- case ')': {
- p->sIn.i--;
- return 0;
- }
- case '(': {
- zErr = re_subcompile_re(p);
- if( zErr ) return zErr;
- if( rePeek(p)!=')' ) return "unmatched '('";
- p->sIn.i++;
- break;
- }
- case '.': {
- if( rePeek(p)=='*' ){
- re_append(p, RE_OP_ANYSTAR, 0);
- p->sIn.i++;
- }else{
- re_append(p, RE_OP_ANY, 0);
- }
- break;
- }
- case '*': {
- if( iPrev<0 ) return "'*' without operand";
- re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
- re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
- break;
- }
- case '+': {
- if( iPrev<0 ) return "'+' without operand";
- re_append(p, RE_OP_FORK, iPrev - p->nState);
- break;
- }
- case '?': {
- if( iPrev<0 ) return "'?' without operand";
- re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
- break;
- }
- case '{': {
- int m = 0, n = 0;
- int sz, j;
- if( iPrev<0 ) return "'{m,n}' without operand";
- while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
- n = m;
- if( c==',' ){
- p->sIn.i++;
- n = 0;
- while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
- }
- if( c!='}' ) return "unmatched '{'";
- if( n>0 && n<m ) return "n less than m in '{m,n}'";
- p->sIn.i++;
- sz = p->nState - iPrev;
- if( m==0 ){
- if( n==0 ) return "both m and n are zero in '{m,n}'";
- re_insert(p, iPrev, RE_OP_FORK, sz+1);
- n--;
- }else{
- for(j=1; j<m; j++) re_copy(p, iPrev, sz);
- }
- for(j=m; j<n; j++){
- re_append(p, RE_OP_FORK, sz+1);
- re_copy(p, iPrev, sz);
- }
- if( n==0 && m>0 ){
- re_append(p, RE_OP_FORK, -sz);
- }
- break;
- }
- case '[': {
- int iFirst = p->nState;
- if( rePeek(p)=='^' ){
- re_append(p, RE_OP_CC_EXC, 0);
- p->sIn.i++;
- }else{
- re_append(p, RE_OP_CC_INC, 0);
- }
- while( (c = p->xNextChar(&p->sIn))!=0 ){
- if( c=='[' && rePeek(p)==':' ){
- return "POSIX character classes not supported";
- }
- if( c=='\\' ) c = re_esc_char(p);
- if( rePeek(p)=='-' ){
- re_append(p, RE_OP_CC_RANGE, c);
- p->sIn.i++;
- c = p->xNextChar(&p->sIn);
- if( c=='\\' ) c = re_esc_char(p);
- re_append(p, RE_OP_CC_RANGE, c);
- }else{
- re_append(p, RE_OP_CC_VALUE, c);
- }
- if( rePeek(p)==']' ){ p->sIn.i++; break; }
- }
- if( c==0 ) return "unclosed '['";
- p->aArg[iFirst] = p->nState - iFirst;
- break;
- }
- case '\\': {
- int specialOp = 0;
- switch( rePeek(p) ){
- case 'b': specialOp = RE_OP_BOUNDARY; break;
- case 'd': specialOp = RE_OP_DIGIT; break;
- case 'D': specialOp = RE_OP_NOTDIGIT; break;
- case 's': specialOp = RE_OP_SPACE; break;
- case 'S': specialOp = RE_OP_NOTSPACE; break;
- case 'w': specialOp = RE_OP_WORD; break;
- case 'W': specialOp = RE_OP_NOTWORD; break;
- }
- if( specialOp ){
- p->sIn.i++;
- re_append(p, specialOp, 0);
- }else{
- c = re_esc_char(p);
- re_append(p, RE_OP_MATCH, c);
- }
- break;
- }
- default: {
- re_append(p, RE_OP_MATCH, c);
- break;
- }
- }
- iPrev = iStart;
- }
- return 0;
- }
- /* Free and reclaim all the memory used by a previously compiled
- ** regular expression. Applications should invoke this routine once
- ** for every call to re_compile() to avoid memory leaks.
- */
- void re_free(ReCompiled *pRe){
- if( pRe ){
- sqlite3_free(pRe->aOp);
- sqlite3_free(pRe->aArg);
- sqlite3_free(pRe);
- }
- }
- /*
- ** Compile a textual regular expression in zIn[] into a compiled regular
- ** expression suitable for us by re_match() and return a pointer to the
- ** compiled regular expression in *ppRe. Return NULL on success or an
- ** error message if something goes wrong.
- */
- const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
- ReCompiled *pRe;
- const char *zErr;
- int i, j;
- *ppRe = 0;
- pRe = sqlite3_malloc( sizeof(*pRe) );
- if( pRe==0 ){
- return "out of memory";
- }
- memset(pRe, 0, sizeof(*pRe));
- pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
- if( re_resize(pRe, 30) ){
- re_free(pRe);
- return "out of memory";
- }
- if( zIn[0]=='^' ){
- zIn++;
- }else{
- re_append(pRe, RE_OP_ANYSTAR, 0);
- }
- pRe->sIn.z = (unsigned char*)zIn;
- pRe->sIn.i = 0;
- pRe->sIn.mx = (int)strlen(zIn);
- zErr = re_subcompile_re(pRe);
- if( zErr ){
- re_free(pRe);
- return zErr;
- }
- if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
- re_append(pRe, RE_OP_MATCH, RE_EOF);
- re_append(pRe, RE_OP_ACCEPT, 0);
- *ppRe = pRe;
- }else if( pRe->sIn.i>=pRe->sIn.mx ){
- re_append(pRe, RE_OP_ACCEPT, 0);
- *ppRe = pRe;
- }else{
- re_free(pRe);
- return "unrecognized character";
- }
- /* The following is a performance optimization. If the regex begins with
- ** ".*" (if the input regex lacks an initial "^") and afterwards there are
- ** one or more matching characters, enter those matching characters into
- ** zInit[]. The re_match() routine can then search ahead in the input
- ** string looking for the initial match without having to run the whole
- ** regex engine over the string. Do not worry able trying to match
- ** unicode characters beyond plane 0 - those are very rare and this is
- ** just an optimization. */
- if( pRe->aOp[0]==RE_OP_ANYSTAR ){
- for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
- unsigned x = pRe->aArg[i];
- if( x<=127 ){
- pRe->zInit[j++] = x;
- }else if( x<=0xfff ){
- pRe->zInit[j++] = 0xc0 | (x>>6);
- pRe->zInit[j++] = 0x80 | (x&0x3f);
- }else if( x<=0xffff ){
- pRe->zInit[j++] = 0xd0 | (x>>12);
- pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
- pRe->zInit[j++] = 0x80 | (x&0x3f);
- }else{
- break;
- }
- }
- if( j>0 && pRe->zInit[j-1]==0 ) j--;
- pRe->nInit = j;
- }
- return pRe->zErr;
- }
- /*
- ** Implementation of the regexp() SQL function. This function implements
- ** the build-in REGEXP operator. The first argument to the function is the
- ** pattern and the second argument is the string. So, the SQL statements:
- **
- ** A REGEXP B
- **
- ** is implemented as regexp(B,A).
- */
- static void re_sql_func(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
- ){
- ReCompiled *pRe; /* Compiled regular expression */
- const char *zPattern; /* The regular expression */
- const unsigned char *zStr;/* String being searched */
- const char *zErr; /* Compile error message */
- int setAux = 0; /* True to invoke sqlite3_set_auxdata() */
- pRe = sqlite3_get_auxdata(context, 0);
- if( pRe==0 ){
- zPattern = (const char*)sqlite3_value_text(argv[0]);
- if( zPattern==0 ) return;
- zErr = re_compile(&pRe, zPattern, 0);
- if( zErr ){
- re_free(pRe);
- sqlite3_result_error(context, zErr, -1);
- return;
- }
- if( pRe==0 ){
- sqlite3_result_error_nomem(context);
- return;
- }
- setAux = 1;
- }
- zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
- if( zStr!=0 ){
- sqlite3_result_int(context, re_match(pRe, zStr, -1));
- }
- if( setAux ){
- sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
- }
- }
- /*
- ** Invoke this routine to register the regexp() function with the
- ** SQLite database connection.
- */
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- int sqlite3_regexp_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
- ){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
- re_sql_func, 0, 0);
- return rc;
- }
|