Combine the implementation of LIKE and GLOB into a single parameterized

function. (CVS 1923)

FossilOrigin-Name: 0a47c8f86d1649e9ae7edd4c49a6fe5f5272351e
This commit is contained in:
drh 2004-08-31 00:52:37 +00:00
parent ee696e2218
commit 4e5ffc5f8d
6 changed files with 144 additions and 478 deletions

View File

@ -1,5 +1,5 @@
C Better\sdetection\sand\shandling\sof\scorrupt\sdatabase\sfiles.\s(CVS\s1922)
D 2004-08-30T16:52:18
C Combine\sthe\simplementation\sof\sLIKE\sand\sGLOB\sinto\sa\ssingle\sparameterized\nfunction.\s(CVS\s1923)
D 2004-08-31T00:52:37
F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -35,7 +35,7 @@ F src/date.c edff4aa851eeca8abbc737dc3933a2f0671156ce
F src/delete.c 0ccc3424d72e5aaded165a8861b9d958c9d0afe6
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c 3694386726ca140dddb839837ba24b58563d10af
F src/func.c 7e2eeebe219aa612ce7a04c74ae6d57379c6656b
F src/func.c ab1d6436edea1333f2a9398800a6404942661724
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c fc1ce65a0fe68f226143de9b43c3582164a92aff
@ -61,7 +61,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 400b2dcc8e05c0101a65a370f7ebb33c9c85f0b3
F src/shell.c 64932b37d79baffd34544172c14c99b2e08a11bb
F src/sqlite.h.in b89ced1acc705bc9c79a2a4e725ac0eb64bd0614
F src/sqliteInt.h c7ed161ecc40f9fd0f080fbcc00e34bd7d6735ee
F src/sqliteInt.h 89c1555ceba68d460ee13530eb8a51944e57fad2
F src/table.c 4521c278892f60e4d630788c0ea5cf4db1e75c49
F src/tclsqlite.c b7dd8b3531b70188d03354db530de0f2ffcac697
F src/test1.c 3670f318c473b5a81cae548d9cc42da3f6a6efee
@ -72,8 +72,8 @@ F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1
F src/tokenize.c 32171c3d576c7ec6acd6cf15e55c00ac0b314769
F src/trigger.c 8b147c6b8ae0bab3a13463a4ca9ab6ad61f1361d
F src/update.c 151f1869ce532ed883f1ce26306f0b0fa7b2589a
F src/utf.c 3d8f7bffcbefcced69a436c9e0a1c7eb9e0bb4fa
F src/util.c e2c631849cc9e035f6fd387f507ad8886f77cedd
F src/utf.c 328890099db492dda5620ee5f924e244c6e57ff7
F src/util.c d5aaf211543fb6e285654fada50252c857ac78aa
F src/vacuum.c 9978a5760c2c430bc5b5e66505a02dad76f25813
F src/vdbe.c bc7717be599d23c463c029d13eb2eb46c94a5e6e
F src/vdbe.h e081c72cd0f7c19d49b1927460aeefcf0fbc85ac
@ -246,7 +246,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 9322c439c5727f0d65548efdf4de4d7b89b4be66
R 78b9eb3fdca60240e1b2bb671f0502fe
P 8f5b199e845fa7ae3444ef69bd840716d305cf73
R 616cb374fb9c8575e09ed1273dacb01d
U drh
Z b8b12d29336c5de9dba049e2bc96808c
Z 33bccfa82a63e9342b9c97917948d9a3

View File

@ -1 +1 @@
8f5b199e845fa7ae3444ef69bd840716d305cf73
0a47c8f86d1649e9ae7edd4c49a6fe5f5272351e

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.80 2004/08/08 20:22:18 drh Exp $
** $Id: func.c,v 1.81 2004/08/31 00:52:37 drh Exp $
*/
#include <ctype.h>
#include <math.h>
@ -298,250 +298,145 @@ static void total_changes(
sqlite3_result_int(context, sqlite3_total_changes(db));
}
#if 0
/*
** A LIKE pattern compiles to an instance of the following structure. Refer
** to the comment for compileLike() function for details.
** A structure defining how to do GLOB-style comparisons.
*/
struct LikePattern {
int nState;
struct LikeState {
int val; /* Unicode codepoint or -1 for any char i.e. '_' */
int failstate; /* State to jump to if next char is not val */
} aState[1];
struct compareInfo {
u8 matchAll;
u8 matchOne;
u8 matchSet;
u8 noCase;
};
typedef struct LikePattern LikePattern;
void deleteLike(void *pLike){
sqliteFree(pLike);
}
/* #define TRACE_LIKE */
#if defined(TRACE_LIKE) && !defined(NDEBUG)
char *dumpLike(LikePattern *pLike){
int i;
int k = 0;
char *zBuf = (char *)sqliteMalloc(pLike->nState*40);
k += sprintf(&zBuf[k], "%d states - ", pLike->nState);
for(i=0; i<pLike->nState; i++){
k += sprintf(&zBuf[k], " %d:(%d, %d)", i, pLike->aState[i].val,
pLike->aState[i].failstate);
}
return zBuf;
}
#endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
/*
** This function compiles an SQL 'LIKE' pattern into a state machine,
** represented by a LikePattern structure.
**
** Each state of the state-machine has two attributes, 'val' and
** 'failstate'. The val attribute is either the value of a unicode
** codepoint, or -1, indicating a '_' wildcard (match any single
** character). The failstate is either the number of another state
** or -1, indicating jump to 'no match'.
**
** To see if a string matches a pattern the pattern is
** compiled to a state machine that is executed according to the algorithm
** below. The string is assumed to be terminated by a 'NUL' character
** (unicode codepoint 0).
**
** 1 S = 0
** 2 DO
** 3 C = <Next character from input string>
** 4 IF( C matches <State S val> )
** 5 S = S+1
** 6 ELSE IF( S != <State S failstate> )
** 7 S = <State S failstate>
** 8 <Rewind Input string 1 character>
** 9 WHILE( (C != NUL) AND (S != FAILED) )
** 10
** 11 IF( S == <number of states> )
** 12 RETURN MATCH
** 13 ELSE
** 14 RETURN NO-MATCH
**
** In practice there is a small optimization to avoid the <Rewind>
** operation in line 8 of the description above.
**
** For example, the following pattern, 'X%ABabc%_Y' is compiled to
** the state machine below.
**
** State Val FailState
** -------------------------------
** 0 120 (x) -1 (NO MATCH)
** 1 97 (a) 1
** 2 98 (b) 1
** 3 97 (a) 1
** 4 98 (b) 2
** 5 99 (c) 3
** 6 -1 (_) 6
** 7 121 (y) 7
** 8 0 (NUL) 7
**
** The algorithms implemented to compile and execute the state machine were
** first presented in "Fast pattern matching in strings", Knuth, Morris and
** Pratt, 1977.
**
** X is a pointer to the first byte of a UTF-8 character. Increment
** X so that it points to the next character. This only works right
** if X points to a well-formed UTF-8 string.
*/
LikePattern *compileLike(sqlite3_value *pPattern, u8 enc){
LikePattern *pLike;
struct LikeState *aState;
int pc_state = -1; /* State number of previous '%' wild card */
int n = 0;
int c;
#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
#define sqliteCharVal(X) sqlite3ReadUtf8(X)
int offset = 0;
const char *zLike;
if( enc==SQLITE_UTF8 ){
zLike = sqlite3_value_text(pPattern);
n = sqlite3_value_bytes(pPattern) + 1;
}else{
zLike = sqlite3_value_text16(pPattern);
n = sqlite3_value_bytes16(pPattern)/2 + 1;
}
pLike = (LikePattern *)
sqliteMalloc(sizeof(LikePattern)+n*sizeof(struct LikeState));
aState = pLike->aState;
n = 0;
do {
c = sqlite3ReadUniChar(zLike, &offset, &enc, 1);
if( c==95 ){ /* A '_' wildcard */
aState[n].val = -1;
n++;
}else if( c==37 ){ /* A '%' wildcard */
aState[n].failstate = n;
pc_state = n;
}else{ /* A regular character */
aState[n].val = c;
assert( pc_state<=n );
if( pc_state<0 ){
aState[n].failstate = -1;
}else if( pc_state==n ){
if( c ){
aState[n].failstate = pc_state;
}else{
aState[n].failstate = -2;
}
}else{
int k = pLike->aState[n-1].failstate;
while( k>pc_state && aState[k+1].val!=-1 && aState[k+1].val!=c ){
k = aState[k].failstate;
}
if( k!=pc_state && aState[k+1].val==c ){
assert( k==pc_state );
k++;
}
aState[n].failstate = k;
}
n++;
}
}while( c );
pLike->nState = n;
#if defined(TRACE_LIKE) && !defined(NDEBUG)
{
char *zCompiled = dumpLike(pLike);
printf("Pattern=\"%s\" Compiled=\"%s\"\n", zPattern, zCompiled);
sqliteFree(zCompiled);
}
#endif
return pLike;
}
/*
** Implementation of the like() SQL function. This function implements
** the build-in LIKE operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression. Return true (1) if they
** are the same and false (0) if they are different.
**
** A LIKE B
** Globbing rules:
**
** is implemented as like(B,A).
** '*' Matches any sequence of zero or more characters.
**
** If the pointer retrieved by via a call to sqlite3_user_data() is
** not NULL, then this function uses UTF-16. Otherwise UTF-8.
** '?' Matches exactly one character.
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
**
** With the [...] and [^...] matching, a ']' character can be included
** in the list by making it the first character after '[' or '^'. A
** range of characters can be specified using '-'. Example:
** "[a-z]" matches any single lower-case letter. To match a '-', make
** it the last character in the list.
**
** This routine is usually quick, but can be N**2 in the worst case.
**
** Hints: to match '*' or '?', put them in "[]". Like this:
**
** abc[*]xyz Matches "abc*xyz" only
*/
static void likeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
int patternCompare(
const u8 *zPattern, /* The glob pattern */
const u8 *zString, /* The string to compare against the glob */
const struct compareInfo *pInfo /* Information about how to do the compare */
){
register int c;
u8 enc;
int offset = 0;
const unsigned char *zString;
LikePattern *pLike = sqlite3_get_auxdata(context, 0);
struct LikeState *aState;
register struct LikeState *pState;
int invert;
int seen;
int c2;
u8 matchOne = pInfo->matchOne;
u8 matchAll = pInfo->matchAll;
u8 matchSet = pInfo->matchSet;
u8 noCase = pInfo->noCase;
/* If either argument is NULL, the result is NULL */
if( sqlite3_value_type(argv[1])==SQLITE_NULL ||
sqlite3_value_type(argv[0])==SQLITE_NULL ){
return;
}
/* If the user-data pointer is NULL, use UTF-8. Otherwise UTF-16. */
if( sqlite3_user_data(context) ){
enc = SQLITE_UTF16NATIVE;
zString = (const unsigned char *)sqlite3_value_text16(argv[1]);
assert(0);
}else{
enc = SQLITE_UTF8;
zString = sqlite3_value_text(argv[1]);
}
/* If the LIKE pattern has not been compiled, compile it now. */
if( !pLike ){
pLike = compileLike(argv[0], enc);
if( !pLike ){
sqlite3_result_error(context, "out of memory", -1);
return;
}
sqlite3_set_auxdata(context, 0, pLike, deleteLike);
}
aState = pLike->aState;
pState = aState;
do {
if( enc==SQLITE_UTF8 ){
c = zString[offset++];
if( c&0x80 ){
offset--;
c = sqlite3ReadUniChar(zString, &offset, &enc, 1);
while( (c = *zPattern)!=0 ){
if( c==matchAll ){
while( (c=zPattern[1]) == matchAll || c == matchOne ){
if( c==matchOne ){
if( *zString==0 ) return 0;
sqliteNextChar(zString);
}
zPattern++;
}
}else{
c = sqlite3ReadUniChar(zString, &offset, &enc, 1);
}
skip_read:
#if defined(TRACE_LIKE) && !defined(NDEBUG)
printf("State=%d:(%d, %d) Input=%d\n",
(aState - pState), pState->val, pState->failstate, c);
#endif
if( pState->val==-1 || pState->val==c ){
pState++;
}else{
struct LikeState *pFailState = &aState[pState->failstate];
if( pState!=pFailState ){
pState = pFailState;
if( c && pState>=aState ) goto skip_read;
if( c==0 ) return 1;
if( c==matchSet ){
while( *zString && patternCompare(&zPattern[1],zString,pInfo)==0 ){
sqliteNextChar(zString);
}
return *zString!=0;
}else{
while( (c2 = *zString)!=0 ){
if( noCase ){
c2 = sqlite3UpperToLower[c2];
c = sqlite3UpperToLower[c];
while( c2 != 0 && c2 != c ){ c2 = sqlite3UpperToLower[*++zString]; }
}else{
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
}
if( c2==0 ) return 0;
if( patternCompare(&zPattern[1],zString,pInfo) ) return 1;
sqliteNextChar(zString);
}
return 0;
}
}else if( c==matchOne ){
if( *zString==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
}else if( c==matchSet ){
int prior_c = 0;
seen = 0;
invert = 0;
c = sqliteCharVal(zString);
if( c==0 ) return 0;
c2 = *++zPattern;
if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = *++zPattern;
}
while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
zPattern++;
c2 = sqliteCharVal(zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else if( c==c2 ){
seen = 1;
prior_c = c2;
}else{
prior_c = c2;
}
sqliteNextChar(zPattern);
}
if( c2==0 || (seen ^ invert)==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
}else{
if( noCase ){
if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
}else{
if( c != *zString ) return 0;
}
zPattern++;
zString++;
}
}while( c && pState>=aState );
if( (pState-aState)==pLike->nState || (pState-aState)<-1 ){
sqlite3_result_int(context, 1);
}else{
sqlite3_result_int(context, 0);
}
return *zString==0;
}
#endif
/*
** Implementation of the like() SQL function. This function implements
@ -563,7 +458,7 @@ static void likeFunc(
const unsigned char *zA = sqlite3_value_text(argv[0]);
const unsigned char *zB = sqlite3_value_text(argv[1]);
if( zA && zB ){
sqlite3_result_int(context, sqlite3utf8LikeCompare(zA, zB));
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo));
}
}
@ -580,7 +475,7 @@ static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
const unsigned char *zA = sqlite3_value_text(argv[0]);
const unsigned char *zB = sqlite3_value_text(argv[1]);
if( zA && zB ){
sqlite3_result_int(context, sqlite3GlobCompare(zA, zB));
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo));
}
}
@ -1016,6 +911,7 @@ static void minMaxFinalize(sqlite3_context *context){
sqlite3VdbeMemRelease(pRes);
}
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.316 2004/08/21 17:54:45 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.317 2004/08/31 00:52:37 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -1270,7 +1270,6 @@ void sqlite3UnlinkAndDeleteIndex(sqlite*,int,const char*);
void sqlite3UnlinkAndDeleteTrigger(sqlite*,int,const char*);
void sqlite3Vacuum(Parse*, Token*);
int sqlite3RunVacuum(char**, sqlite*);
int sqlite3GlobCompare(const unsigned char*,const unsigned char*);
char *sqlite3NameFromToken(Token*);
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
int sqlite3ExprCompare(Expr*, Expr*);
@ -1354,7 +1353,7 @@ int sqlite3GetInt32(const char *, int*);
int sqlite3FitsIn64Bits(const char *);
int sqlite3utf16ByteLen(const void *pData, int nChar);
int sqlite3utf8CharLen(const char *pData, int nByte);
int sqlite3utf8LikeCompare(const unsigned char*, const unsigned char*);
int sqlite3ReadUtf8(const unsigned char *);
int sqlite3PutVarint(unsigned char *, u64);
int sqlite3GetVarint(const unsigned char *, u64 *);
int sqlite3GetVarint32(const unsigned char *, u32 *);
@ -1388,5 +1387,6 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew();
sqlite3_value *sqlite3GetTransientValue(sqlite *db);
extern const unsigned char sqlite3UpperToLower[];
#endif

View File

@ -12,7 +12,7 @@
** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id: utf.c,v 1.27 2004/08/08 23:39:19 drh Exp $
** $Id: utf.c,v 1.28 2004/08/31 00:52:37 drh Exp $
**
** Notes on UTF-8:
**
@ -62,27 +62,6 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** The following macro, LOWERCASE(x), takes an integer representing a
** unicode code point. The value returned is the same code point folded to
** lower case, if applicable. SQLite currently understands the upper/lower
** case relationship between the 26 characters used in the English
** language only.
**
** This means that characters with umlauts etc. will not be folded
** correctly (unless they are encoded as composite characters, which would
** doubtless cause much trouble).
*/
#define LOWERCASE(x) (x<91?(int)(UpperToLower[x]):x)
static unsigned char UpperToLower[91] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
122,
};
/*
** This table maps from the first byte of a UTF-8 character to the number
** of trailing bytes expected. A value '255' indicates that the table key
@ -141,6 +120,11 @@ static const int xtra_utf8_bits[4] = {
c -= xtra_utf8_bits[xtra]; \
} \
}
int sqlite3ReadUtf8(const unsigned char *z){
int c;
READ_UTF8(z, c);
return c;
}
#define SKIP_UTF8(zIn) { \
zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
@ -491,59 +475,6 @@ int sqlite3utf16ByteLen(const void *zIn, int nChar){
return (z-(char const *)zIn)-((c==0)?2:0);
}
/*
** Compare two UTF-8 strings for equality using the "LIKE" operator of
** SQL. The '%' character matches any sequence of 0 or more
** characters and '_' matches any single character. Case is
** not significant.
*/
int sqlite3utf8LikeCompare(
const unsigned char *zPattern,
const unsigned char *zString
){
register int c;
int c2;
while( (c = LOWERCASE(*zPattern))!=0 ){
switch( c ){
case '%': {
while( (c=zPattern[1]) == '%' || c == '_' ){
if( c=='_' ){
if( *zString==0 ) return 0;
SKIP_UTF8(zString);
}
zPattern++;
}
if( c==0 ) return 1;
c = LOWERCASE(c);
while( (c2=LOWERCASE(*zString))!=0 ){
while( c2 != 0 && c2 != c ){
zString++;
c2 = LOWERCASE(*zString);
}
if( c2==0 ) return 0;
if( sqlite3utf8LikeCompare(&zPattern[1],zString) ) return 1;
SKIP_UTF8(zString);
}
return 0;
}
case '_': {
if( *zString==0 ) return 0;
SKIP_UTF8(zString);
zPattern++;
break;
}
default: {
if( c != LOWERCASE(*zString) ) return 0;
zPattern++;
zString++;
break;
}
}
}
return *zString==0;
}
/*
** UTF-16 implementation of the substr()
*/

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.113 2004/08/18 02:10:15 drh Exp $
** $Id: util.c,v 1.114 2004/08/31 00:52:37 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -533,7 +533,7 @@ void sqlite3Dequote(char *z){
/* An array to map all upper-case characters into their corresponding
** lower-case character.
*/
static unsigned char UpperToLower[] = {
const unsigned char sqlite3UpperToLower[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
@ -550,6 +550,7 @@ static unsigned char UpperToLower[] = {
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255
};
#define UpperToLower sqlite3UpperToLower
/*
** This function computes a hash on the name of a keyword.
@ -762,168 +763,6 @@ int sqlite3FitsIn64Bits(const char *zNum){
return i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0);
}
#if 1 /* We are now always UTF-8 */
/*
** X is a pointer to the first byte of a UTF-8 character. Increment
** X so that it points to the next character. This only works right
** if X points to a well-formed UTF-8 string.
*/
#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
#define sqliteCharVal(X) sqlite3ReadUtf8(X)
#else /* !defined(SQLITE_UTF8) */
/*
** For iso8859 encoding, the next character is just the next byte.
*/
#define sqliteNextChar(X) (++(X));
#define sqliteCharVal(X) ((int)*(X))
#endif /* defined(SQLITE_UTF8) */
#if 1 /* We are now always UTF-8 */
/*
** Convert the UTF-8 character to which z points into a 31-bit
** UCS character. This only works right if z points to a well-formed
** UTF-8 string.
*/
int sqlite3ReadUtf8(const unsigned char *z){
int c;
static const char initVal[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 0, 1, 254,
255,
};
c = initVal[*(z++)];
while( (0xc0&*z)==0x80 ){
c = (c<<6) | (0x3f&*(z++));
}
return c;
}
#endif
/*
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression. Return true (1) if they
** are the same and false (0) if they are different.
**
** Globbing rules:
**
** '*' Matches any sequence of zero or more characters.
**
** '?' Matches exactly one character.
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
**
** With the [...] and [^...] matching, a ']' character can be included
** in the list by making it the first character after '[' or '^'. A
** range of characters can be specified using '-'. Example:
** "[a-z]" matches any single lower-case letter. To match a '-', make
** it the last character in the list.
**
** This routine is usually quick, but can be N**2 in the worst case.
**
** Hints: to match '*' or '?', put them in "[]". Like this:
**
** abc[*]xyz Matches "abc*xyz" only
*/
int
sqlite3GlobCompare(const unsigned char *zPattern, const unsigned char *zString){
register int c;
int invert;
int seen;
int c2;
while( (c = *zPattern)!=0 ){
switch( c ){
case '*':
while( (c=zPattern[1]) == '*' || c == '?' ){
if( c=='?' ){
if( *zString==0 ) return 0;
sqliteNextChar(zString);
}
zPattern++;
}
if( c==0 ) return 1;
if( c=='[' ){
while( *zString && sqlite3GlobCompare(&zPattern[1],zString)==0 ){
sqliteNextChar(zString);
}
return *zString!=0;
}else{
while( (c2 = *zString)!=0 ){
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
if( c2==0 ) return 0;
if( sqlite3GlobCompare(&zPattern[1],zString) ) return 1;
sqliteNextChar(zString);
}
return 0;
}
case '?': {
if( *zString==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
break;
}
case '[': {
int prior_c = 0;
seen = 0;
invert = 0;
c = sqliteCharVal(zString);
if( c==0 ) return 0;
c2 = *++zPattern;
if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = *++zPattern;
}
while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
zPattern++;
c2 = sqliteCharVal(zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else if( c==c2 ){
seen = 1;
prior_c = c2;
}else{
prior_c = c2;
}
sqliteNextChar(zPattern);
}
if( c2==0 || (seen ^ invert)==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
break;
}
default: {
if( c != *zString ) return 0;
zPattern++;
zString++;
break;
}
}
}
return *zString==0;
}
/*
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.