diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c new file mode 100644 index 000000000..130634547 --- /dev/null +++ b/src/util.c @@ -0,0 +1,445 @@ +/* +** Copyright (c) 1999, 2000 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +************************************************************************* +** Utility functions used throughout sqlite. +** +** This file contains functions for allocating memory, comparing +** strings, and stuff like that. +** +** $Id: util.c,v 1.1 2000/05/29 14:26:02 drh Exp $ +*/ +#include "sqliteInt.h" +#include <stdarg.h> +#include <ctype.h> + +/* +** Allocate new memory and set it to zero. Return NULL if +** no memory is available. +*/ +void *sqliteMalloc(int n){ + void *p = malloc(n); + if( p==0 ) return 0; + memset(p, 0, n); + return p; +} + +/* +** Free memory previously obtained from sqliteMalloc() +*/ +void sqliteFree(void *p){ + if( p ) free(p); +} + +/* +** Resize a prior allocation. If p==0, then this routine +** works just like sqliteMalloc(). If n==0, then this routine +** works just like sqliteFree(). +*/ +void *sqliteRealloc(void *p, int n){ + if( p==0 ){ + return sqliteMalloc(n); + } + if( n==0 ){ + sqliteFree(p); + return 0; + } + return realloc(p, n); +} + +/* +** Create a string from the 2nd and subsequent arguments (up to the +** first NULL argument), store the string in memory obtained from +** sqliteMalloc() and make the pointer indicated by the 1st argument +** point to that string. +*/ +void sqliteSetString(char **pz, const char *zFirst, ...){ + va_list ap; + int nByte; + const char *z; + char *zResult; + + if( pz==0 ) return; + nByte = strlen(zFirst) + 1; + va_start(ap, zFirst); + while( (z = va_arg(ap, const char*))!=0 ){ + nByte += strlen(z); + } + va_end(ap); + sqliteFree(*pz); + *pz = zResult = sqliteMalloc( nByte ); + if( zResult==0 ) return; + strcpy(zResult, zFirst); + zResult += strlen(zResult); + va_start(ap, zFirst); + while( (z = va_arg(ap, const char*))!=0 ){ + strcpy(zResult, z); + zResult += strlen(zResult); + } + va_end(ap); +} + +/* +** Works like sqliteSetString, but each string is now followed by +** a length integer. -1 means use the whole string. +*/ +void sqliteSetNString(char **pz, ...){ + va_list ap; + int nByte; + const char *z; + char *zResult; + int n; + + if( pz==0 ) return; + nByte = 0; + va_start(ap, pz); + while( (z = va_arg(ap, const char*))!=0 ){ + n = va_arg(ap, int); + if( n<=0 ) n = strlen(z); + nByte += n; + } + va_end(ap); + sqliteFree(*pz); + *pz = zResult = sqliteMalloc( nByte + 1 ); + if( zResult==0 ) return; + va_start(ap, pz); + while( (z = va_arg(ap, const char*))!=0 ){ + n = va_arg(ap, int); + if( n<=0 ) n = strlen(z); + strncpy(zResult, z, n); + zResult += n; + } + *zResult = 0; + va_end(ap); +} + +/* An array to map all upper-case characters into their corresponding +** lower-case character. +*/ +static unsigned char UpperToLower[] = { + 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, 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,192,193,194,195,196,197, + 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 +}; + +/* +** This function computes a hash on the name of a keyword. +** Case is not significant. +*/ +int sqliteHashNoCase(const char *z, int n){ + int h = 0; + int c; + if( n<=0 ) n = strlen(z); + while( n-- > 0 && (c = *z++)!=0 ){ + h = h<<3 ^ h ^ UpperToLower[c]; + } + if( h<0 ) h = -h; + return h; +} + +/* +** Some system shave stricmp(). Others have strcasecmp(). Because +** there is no consistency, we will define our own. +*/ +int sqliteStrICmp(const char *zLeft, const char *zRight){ + register unsigned char *a, *b; + a = (unsigned char *)zLeft; + b = (unsigned char *)zRight; + while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } + return *a - *b; +} +int sqliteStrNICmp(const char *zLeft, const char *zRight, int N){ + register unsigned char *a, *b; + a = (unsigned char *)zLeft; + b = (unsigned char *)zRight; + while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } + return N<=0 ? 0 : *a - *b; +} + +/* Notes on string comparisions. +** +** We want the main string comparision function used for sorting to +** sort both numbers and alphanumeric words into the correct sequence. +** The same routine should do both without prior knowledge of which +** type of text the input represents. It should even work for strings +** which are a mixture of text and numbers. +** +** To accomplish this, we keep track of a state number while scanning +** the two strings. The states are as follows: +** +** 1 Beginning of word +** 2 Arbitrary text +** 3 Integer +** 4 Negative integer +** 5 Real number +** 6 Negative real +** +** The scan begins in state 1, beginning of word. Transitions to other +** states are determined by characters seen, as shown in the following +** chart: +** +** Current State Character Seen New State +** -------------------- -------------- ------------------- +** 0 Beginning of word "-" 3 Negative integer +** digit 2 Integer +** space 0 Beginning of word +** otherwise 1 Arbitrary text +** +** 1 Arbitrary text space 0 Beginning of word +** digit 2 Integer +** otherwise 1 Arbitrary text +** +** 2 Integer space 0 Beginning of word +** "." 4 Real number +** digit 2 Integer +** otherwise 1 Arbitrary text +** +** 3 Negative integer space 0 Beginning of word +** "." 5 Negative Real num +** digit 3 Negative integer +** otherwise 1 Arbitrary text +** +** 4 Real number space 0 Beginning of word +** digit 4 Real number +** otherwise 1 Arbitrary text +** +** 5 Negative real num space 0 Beginning of word +** digit 5 Negative real num +** otherwise 1 Arbitrary text +** +** To implement this state machine, we first classify each character +** into on of the following categories: +** +** 0 Text +** 1 Space +** 2 Digit +** 3 "-" +** 4 "." +** +** Given an arbitrary character, the array charClass[] maps that character +** into one of the atove categories. +*/ +static const unsigned char charClass[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ +/* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, +/* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 2x */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0, +/* 3x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, +/* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define N_CHAR_CLASS 5 + +/* +** Given the current state number (0 thru 5), this array figures +** the new state number given the character class. +*/ +static const unsigned char stateMachine[] = { + /* Text, Space, Digit, "-", "." */ + 1, 0, 2, 3, 1, /* State 0: Beginning of word */ + 1, 0, 2, 1, 1, /* State 1: Arbitrary text */ + 1, 0, 2, 1, 4, /* State 2: Integer */ + 1, 0, 3, 1, 5, /* State 3: Negative integer */ + 1, 0, 4, 1, 1, /* State 4: Real number */ + 1, 0, 5, 1, 1, /* State 5: Negative real num */ +}; + +/* This routine does a comparison of two strings. Case is used only +** if useCase!=0. Numbers compare in numerical order. +*/ +static int privateStrCmp(const char *atext, const char *btext, int useCase){ + register unsigned char *a, *b, *map, ca, cb; + int result; + register int cclass = 0; + + a = (unsigned char *)atext; + b = (unsigned char *)btext; + if( useCase ){ + do{ + if( (ca= *a++)!=(cb= *b++) ) break; + cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]]; + }while( ca!=0 ); + }else{ + map = UpperToLower; + do{ + if( (ca=map[*a++])!=(cb=map[*b++]) ) break; + cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]]; + }while( ca!=0 ); + } + switch( cclass ){ + case 0: + case 1: { + if( isdigit(ca) && isdigit(cb) ){ + cclass = 2; + } + break; + } + default: { + break; + } + } + switch( cclass ){ + case 2: + case 3: { + if( isdigit(ca) ){ + if( isdigit(cb) ){ + int acnt, bcnt; + acnt = bcnt = 0; + while( isdigit(*a++) ) acnt++; + while( isdigit(*b++) ) bcnt++; + result = acnt - bcnt; + if( result==0 ) result = ca-cb; + }else{ + result = 1; + } + }else if( isdigit(cb) ){ + result = -1; + }else if( ca=='.' ){ + result = 1; + }else if( cb=='.' ){ + result = -1; + }else{ + result = ca - cb; + cclass = 2; + } + if( cclass==3 ) result = -result; + break; + } + case 0: + case 1: + case 4: { + result = ca - cb; + break; + } + case 5: { + result = cb - ca; + }; + } + return result; +} + +/* This comparison routine is what we use for comparison operations +** in an SQL expression. (Ex: name<'Hello' or value<5). Compare two +** strings. Use case only as a tie-breaker. Numbers compare in +** numerical order. +*/ +int sqliteCompare(const char *atext, const char *btext){ + int result; + result = privateStrCmp(atext, btext, 0); + if( result==0 ) result = privateStrCmp(atext, btext, 1); + return result; +} + +/* +** If you compile just this one file with the -DTEST_COMPARE=1 option, +** it generates a program to test the comparisons routines. +*/ +#ifdef TEST_COMPARE +#include <stdlib.h> +#include <stdio.h> +int sortCmp(const char **a, const char **b){ + return sqliteCompare(*a, *b); +} +int main(int argc, char **argv){ + int i, j, k, n; + static char *azStr[] = { + "abc", "aBc", "abcd", "aBcd", + "123", "124", "1234", "-123", "-124", "-1234", + "123.45", "123.456", "123.46", "-123.45", "-123.46", "-123.456", + "x9", "x10", "x-9", "x-10", "X9", "X10", + }; + n = sizeof(azStr)/sizeof(azStr[0]); + qsort(azStr, n, sizeof(azStr[0]), sortCmp); + for(i=0; i<n; i++){ + printf("%s\n", azStr[i]); + } + printf("Sanity1..."); + fflush(stdout); + for(i=0; i<n-1; i++){ + char *a = azStr[i]; + for(j=i+1; j<n; j++){ + char *b = azStr[j]; + if( sqliteCompare(a,b) != -sqliteCompare(b,a) ){ + printf("Failed! \"%s\" vs \"%s\"\n", a, b); + i = j = n; + } + } + } + if( i<n ){ + printf(" OK\n"); + } + return 0; +} +#endif + +/* +** This routine is used for sorting. Each key is a list one or more +** null-terminated strings. The list is terminated by two null in +** a row. For example, the following text is strings: +** +** +one\000-two\000+three\000\000 +** +** Both arguments will have the same number of strings. This routine +** returns negative, zero, or positive if the first argument is less +** than, equal to, or greater than the first. (Result is a-b). +** +** Every string begins with either a "+" or "-" character. If the +** character is "-" then the return value is negated. This is done +** to implement a sort in descending order. +*/ +int sqliteSortCompare(const char *a, const char *b){ + int len; + int res = 0; + + while( res==0 && *a && *b ){ + res = sqliteCompare(&a[1], &b[1]); + if( res==0 ){ + len = strlen(a) + 1; + a += len; + b += len; + } + } + if( *a=='-' ) res = -res; + return res; +} |