blob: 4aaf0058f2d8b5fb72b4417a04a2cb1d0dc7419d [file] [log] [blame] [edit]
/*
** 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 0 /* Match the one character in the argument */
#define RE_OP_ANY 1 /* Match any one character. (Implements ".") */
#define RE_OP_CC_INC 2 /* Beginning of a [...] character class */
#define RE_OP_CC_EXC 3 /* Beginning of a [^...] character class */
#define RE_OP_CC_VALUE 4 /* Single value in a character class */
#define RE_OP_CC_RANGE 5 /* Range of values in a character class */
#define RE_OP_WORD 6 /* Perl word character [A-Za-z0-9_] */
#define RE_OP_NOTWORD 7 /* Not a perl word character */
#define RE_OP_DIGIT 8 /* digit: [0-9] */
#define RE_OP_NOTDIGIT 9 /* Not a digit */
#define RE_OP_SPACE 10 /* space: [ \t\n\r\v\f] */
#define RE_OP_NOTSPACE 11 /* Not a digit */
#define RE_IMMEDIATE 12 /* OPs >= this evaluate immediately */
#define RE_OP_BOUNDARY 12 /* Boundary between word and non-word */
#define RE_OP_FORK 13 /* Continue to both next and opcode at iArg */
#define RE_OP_GOTO 14 /* Jump to opcode at iArg */
#define RE_OP_ACCEPT 15 /* Halt and indicate a successful match */
/* 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.
**
** The application must serialize access to this object. The code here
** is threadsafe, as long as each thread is using its own ReCompiled object.
** But a single ReCompiled object is neither threadsafe nor reentrant.
**
** The iBegin value is the earliest possible start of the match. The
** true start of the match might be later.
*/
typedef struct ReCompiled ReCompiled;
struct ReCompiled {
ReInput sIn; /* Regexp text, or match string text */
const char *zErr; /* Error message to return */
char *aOp; /* Operators for the virtual machine */
int *aArg; /* Arguments to each operator */
ReStateSet a, b; /* Used by re_match() */
unsigned (*xNextChar)(ReInput*); /* Next character function */
unsigned char nInit; /* Number of characters in zInit */
unsigned char bFlexStart; /* Input regexp omits the initial "^" */
unsigned char bKeepSpan; /* When matching, remember start and end */
unsigned char bMultiBegin; /* iBegin might not be accurate */
unsigned int iBegin; /* Offset to first character in the match */
unsigned int iEnd; /* Offset past the end of last match char */
unsigned int nState; /* Number of entries in aOp[] and aArg[] */
unsigned int nAlloc; /* Slots allocated for aOp[] and aArg[] */
unsigned char zInit[12]; /* Initial text to match */
};
#if SQLITE_REGEXP_DEBUG
/************************************************************************
** The following interfaces are used for development and debugging only
** and are commented out for deployment.
*/
#include <stdio.h>
#include <ctype.h>
/* Render one character. */
static char *re_char(int c){
static char zBuf[20];
if( isprint(c) && (c==' ' || !isspace(c)) ){
sqlite3_snprintf(sizeof(zBuf),zBuf,"'%c'",c);
}else{
sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",c);
}
return zBuf;
}
/*
** Print out a regexp program.
*/
static void re_print(ReCompiled *pRe){
int i;
for(i=0; i<pRe->nState; i++){
printf("%3d ", i);
switch( pRe->aOp[i] ){
case RE_OP_MATCH: printf("MATCH %s\n", re_char(pRe->aArg[i]));
break;
case RE_OP_ANY: printf("ANY\n"); break;
case RE_OP_WORD: printf("WORD\n"); break;
case RE_OP_NOTWORD: printf("NOTWORD\n"); break;
case RE_OP_DIGIT: printf("DIGIT\n"); break;
case RE_OP_NOTDIGIT: printf("NOTDIGIT\n"); break;
case RE_OP_SPACE: printf("SPACE\n"); break;
case RE_OP_NOTSPACE: printf("NOTSPACE\n"); break;
case RE_OP_BOUNDARY: printf("BOUNDARY\n"); break;
case RE_OP_FORK: printf("FORK %d\n", i+pRe->aArg[i]); break;
case RE_OP_GOTO: printf("GOTO %d\n", i+pRe->aArg[i]); break;
case RE_OP_ACCEPT: printf("ACCEPT\n"); break;
case RE_OP_CC_INC:
case RE_OP_CC_EXC: {
printf("%s\n", pRe->aOp[i]==RE_OP_CC_INC ? "CC_INC" : "CC_EXC");
int j;
int n = pRe->aArg[i];
for(j=1; j>0 && j<n; j++){
printf("%3d ... %s %s\n", i+j,
pRe->aOp[i+j]==RE_OP_CC_VALUE ? "VALUE" : "RANGE",
re_char(pRe->aArg[i+j]));
}
i += n-1;
break;
}
}
}
}
/*
** Print out a ReStateSet
*/
static void restateset_print(ReStateSet *pSet){
int i;
for(i=0; i<pSet->nState; i++){
if( i ) printf(" ");
printf(" %2d", pSet->aState[i]);
}
}
/* End of debugging utilities
*****************************************************************************/
#endif /* SQLITE_REGEXP_DEBUG */
/* Add a state to the given state set if it is not already there */
static void re_add_state_to_set(ReStateSet *pSet, int newState){
unsigned i;
for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
pSet->aState[pSet->nState++] = (ReStateNumber)newState;
}
/* Add a state to the appropriate state set. States for immediate
** evaluation are added into pRe->a. If another input token is required
** before the state can be evaluated, then it is added to pRe->b.
*/
static void re_add_state(ReCompiled *pRe, int newState){
ReStateSet *pSet;
if( pRe->aOp[newState]>=RE_IMMEDIATE ){
pSet = &pRe->a;
}else{
pSet = &pRe->b;
}
re_add_state_to_set(pSet, 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';
}
/* Interchange pRe->a and pRe->b */
static void re_swap(ReCompiled *pRe){
ReStateSet t = pRe->a;
pRe->a = pRe->b;
pRe->b = t;
}
/* 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){
unsigned int i = 0;
int c = RE_EOF+1;
int rc = 0;
int iIdx = -1;
int iBegin = -1;
int iReset = -1;
ReInput *pIn = &pRe->sIn;
pIn->z = zIn;
pIn->i = 0;
pIn->mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn);
pRe->bMultiBegin = 0;
/* Look for the initial prefix match, if there is one. */
if( pRe->nInit ){
unsigned char x = pRe->zInit[0];
while( pIn->i+pRe->nInit<=pIn->mx
&& (zIn[pIn->i]!=x ||
strncmp((const char*)zIn+pIn->i,
(const char*)pRe->zInit,pRe->nInit)!=0)
){
pIn->i++;
}
if( pIn->i+pRe->nInit>pIn->mx ) return 0;
}
re_print(pRe);
printf("INPUT: [%.*s]\n", nIn, zIn);
pRe->b.nState = 0;
pRe->a.nState = 0;
re_add_state(pRe, 0);
iReset = -1;
c = 0;
while(1){
for(i=0; i<pRe->a.nState; i++){
int x = pRe->a.aState[i];
printf("%2d,%-5s %d.%d = ", pRe->sIn.i, re_char(c), i, x);
restateset_print(&pRe->a);
printf(" => ");
restateset_print(&pRe->b);
printf("\n");
switch( pRe->aOp[x] ){
case RE_OP_MATCH: {
if( pRe->aArg[x]!=c ) break;
/* Fall thru */
}
case RE_OP_ANY: {
add_next:
re_add_state(pRe, x+1);
break;
}
case RE_OP_WORD: {
if( re_word_char(c) ) goto add_next;
break;
}
case RE_OP_NOTWORD: {
if( !re_word_char(c) ) goto add_next;
break;
}
case RE_OP_DIGIT: {
if( re_digit_char(c) ) goto add_next;
break;
}
case RE_OP_NOTDIGIT: {
if( !re_digit_char(c) ) goto add_next;
break;
}
case RE_OP_SPACE: {
if( re_space_char(c) ) goto add_next;
break;
}
case RE_OP_NOTSPACE: {
if( !re_space_char(c) ) goto add_next;
break;
}
case RE_OP_BOUNDARY: {
int iCur = pIn->i;
int cNext = pRe->xNextChar(pIn);
pIn->i = iCur;
if( re_word_char(c)!=re_word_char(cNext) ){
if( iReset>=0 ) goto add_next;
re_add_state_to_set(&pRe->b, x);
}
break;
}
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(pRe, x+n);
break;
}
case RE_OP_FORK: {
re_add_state(pRe, x+1);
/* Fall thru */
}
case RE_OP_GOTO: {
re_add_state(pRe, x+pRe->aArg[x]);
break;
}
case RE_OP_ACCEPT: {
if( !pRe->bKeepSpan ) return 1;
pRe->iEnd = pIn->i;
printf("ACCEPT %d\n", pIn->i);
rc = 1;
break;
}
} /* End of switch( pRe->aOp[x] ) */
} /* End of loop over states in pRe->a.aState[] */
if( iReset<0 ){
if( pRe->bFlexStart ){
iReset = pRe->b.nState;
memcpy(pRe->a.aState, pRe->b.aState, iReset*sizeof(ReStateNumber));
}else{
iReset = 0;
}
printf("iReset=%d\n", iReset);
}else if( c==RE_EOF || pRe->b.nState==0 ){
break;
}else if( pRe->b.nState>iReset ){
if( iBegin<0 ){
iBegin = iIdx;
printf("Begin at %d\n", iIdx);
}else{
pRe->bMultiBegin = 1;
printf("Another possible beginning: %d\n", iIdx);
}
}
re_swap(pRe);
pRe->b.nState = iReset;
iIdx = pIn->i;
c = pRe->xNextChar(pIn);
}
pRe->iBegin = iBegin;
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] = (char)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 '.': {
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->a.aState);
sqlite3_free(pRe->b.aState);
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{
pRe->bFlexStart = 1;
}
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";
}
pRe->a.aState = sqlite3_malloc64( sizeof(pRe->a.aState[0])*pRe->nState );
pRe->b.aState = sqlite3_malloc64( sizeof(pRe->b.aState[0])*pRe->nState );
if( pRe->a.aState==0 || pRe->b.aState==0 ){
re_free(pRe);
return "out of memory";
}
/* 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->bFlexStart && !noCase ){
for(j=0, i=0; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
unsigned x = pRe->aArg[i];
if( x<=127 ){
pRe->zInit[j++] = (unsigned char)x;
}else if( x<=0xfff ){
pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6));
pRe->zInit[j++] = 0x80 | (x&0x3f);
}else if( x<=0xffff ){
pRe->zInit[j++] = (unsigned char)(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);
}
}
/*
** Implementation of the regexp_test1() SQL function.
**
** regexp_test1(PATTERN, STRING)
**
** Return the part of STRING that matches PATTERN. Or return NULL
** if there is no match.
*/
static void re_test1_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() */
int rc;
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 ){
int iBegin, iEnd;
pRe->bKeepSpan = 1;
rc = re_match(pRe, zStr, -1);
if( !rc ) goto re_test1_end;
iBegin = pRe->iBegin;
iEnd = pRe->iEnd;
if( pRe->bMultiBegin ){
pRe->bKeepSpan = 0;
while( re_match(pRe, zStr+iBegin, iEnd-iBegin)==0 ){
if( zStr[++iBegin]>=0xc0 ){
while( (zStr[iBegin]&0xc0)==0x80 ) iBegin++;
}
if( iBegin>=iEnd ) goto re_test1_end;
}
}
sqlite3_result_text(context, (const char*)zStr+iBegin,
iEnd - iBegin, SQLITE_TRANSIENT);
}
re_test1_end:
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);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "re_test1", 2, SQLITE_UTF8, 0,
re_test1_func, 0, 0);
}
return rc;
}