Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** 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 #include #include #include @@ -296,254 +296,149 @@ ){ sqlite *db = sqlite3_user_data(context); 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; inState; i++){ - k += sprintf(&zBuf[k], " %d:(%d, %d)", i, pLike->aState[i].val, - pLike->aState[i].failstate); - } - return zBuf; -} -#endif - -/* -** 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 = -** 4 IF( C matches ) -** 5 S = S+1 -** 6 ELSE IF( S != ) -** 7 S = -** 8 -** 9 WHILE( (C != NUL) AND (S != FAILED) ) -** 10 -** 11 IF( S == ) -** 12 RETURN MATCH -** 13 ELSE -** 14 RETURN NO-MATCH -** -** In practice there is a small optimization to avoid the -** 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. -** -*/ -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; - - 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: -** -** A LIKE B -** -** is implemented as like(B,A). -** -** If the pointer retrieved by via a call to sqlite3_user_data() is -** not NULL, then this function uses UTF-16. Otherwise UTF-8. -*/ -static void likeFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv +static const struct compareInfo globInfo = { '*', '?', '[', 0 }; +static const struct compareInfo likeInfo = { '%', '_', 0, 1 }; + +/* +** 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) + + +/* +** 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 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; - - /* 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); - } - }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; - } - } - }while( c && pState>=aState ); - - if( (pState-aState)==pLike->nState || (pState-aState)<-1 ){ - sqlite3_result_int(context, 1); - }else{ - sqlite3_result_int(context, 0); - } -} -#endif + int invert; + int seen; + int c2; + u8 matchOne = pInfo->matchOne; + u8 matchAll = pInfo->matchAll; + u8 matchSet = pInfo->matchSet; + u8 noCase = pInfo->noCase; + + 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++; + } + 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++; + } + } + return *zString==0; +} + /* ** 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: @@ -561,11 +456,11 @@ 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, sqlite3utf8LikeCompare(zA, zB)); + sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo)); } } /* ** Implementation of the glob() SQL function. This function implements @@ -578,11 +473,11 @@ */ 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)); } } /* ** Implementation of the NULLIF(x,y) function. The result is the first @@ -1013,10 +908,11 @@ if( pRes->flags ){ sqlite3_result_value(context, pRes); } sqlite3VdbeMemRelease(pRes); } + /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** 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_ #include "config.h" @@ -1268,11 +1268,10 @@ void sqlite3UnlinkAndDeleteTable(sqlite*,int,const char*); 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*); int sqliteFuncId(Token*); int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*); @@ -1352,11 +1351,11 @@ char *sqlite3_snprintf(int,char*,const char*,...); 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 *); int sqlite3VarintLen(u64 v); char sqlite3AffinityType(const char *, int); @@ -1386,7 +1385,8 @@ int sqlite3ValueBytes(sqlite3_value*, u8); 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 Index: src/utf.c ================================================================== --- src/utf.c +++ src/utf.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** 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: ** ** Byte-0 Byte-1 Byte-2 Byte-3 Value ** 0xxxxxxx 00000000 00000000 0xxxxxxx @@ -60,31 +60,10 @@ */ #include #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 ** is not a legal first byte for a UTF-8 character. */ @@ -138,10 +117,15 @@ case 3: c = (c<<6) + *(zIn)++; \ case 2: c = (c<<6) + *(zIn)++; \ case 1: c = (c<<6) + *(zIn)++; \ 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); \ } @@ -489,63 +473,10 @@ } } 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() */ void sqlite3utf16Substr( sqlite3_context *context, Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -12,11 +12,11 @@ ** Utility functions used throughout sqlite. ** ** 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 #include @@ -531,11 +531,11 @@ } /* 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, 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, @@ -548,10 +548,11 @@ 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, 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. ** Case is not significant. */ @@ -760,172 +761,10 @@ if( *zNum=='-' || *zNum=='+' ) zNum++; for(i=0; (c=zNum[i])>='0' && c<='9'; i++){} 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. ** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN ** when this routine is called.