📄 util.c
字号:
nByte += n; } va_end(ap); sqliteFree(*pz); *pz = zResult = sqliteMallocRaw( 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;#ifdef MEMORY_DEBUG#if MEMORY_DEBUG>1 fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);#endif#endif va_end(ap);}/*** Add an error message to pParse->zErrMsg and increment pParse->nErr.** The following formatting characters are allowed:**** %s Insert a string** %z A string that should be freed after use** %d Insert an integer** %T Insert a token** %S Insert the first element of a SrcList*/void sqliteErrorMsg(Parse *pParse, const char *zFormat, ...){ va_list ap; int nByte; int i, j; char *z; static char zNull[] = "NULL"; pParse->nErr++; nByte = 1 + strlen(zFormat); va_start(ap, zFormat); for(i=0; zFormat[i]; i++){ if( zFormat[i]!='%' || zFormat[i+1]==0 ) continue; i++; switch( zFormat[i] ){ case 'd': { (void)va_arg(ap, int); nByte += 20; break; } case 'z': case 's': { char *z2 = va_arg(ap, char*); if( z2==0 ) z2 = zNull; nByte += strlen(z2); break; } case 'T': { Token *p = va_arg(ap, Token*); nByte += p->n; break; } case 'S': { SrcList *p = va_arg(ap, SrcList*); int k = va_arg(ap, int); assert( p->nSrc>k && k>=0 ); nByte += strlen(p->a[k].zName); if( p->a[k].zDatabase && p->a[k].zDatabase[0] ){ nByte += strlen(p->a[k].zDatabase)+1; } break; } default: { nByte++; break; } } } va_end(ap); z = sqliteMalloc( nByte ); if( z==0 ) return; sqliteFree(pParse->zErrMsg); pParse->zErrMsg = z; va_start(ap, zFormat); for(i=j=0; zFormat[i]; i++){ if( zFormat[i]!='%' || zFormat[i+1]==0 ) continue; if( i>j ){ memcpy(z, &zFormat[j], i-j); z += i-j; } j = i+2; i++; switch( zFormat[i] ){ case 'd': { int x = va_arg(ap, int); sprintf(z, "%d", x); z += strlen(z); break; } case 'z': case 's': { int len; char *z2 = va_arg(ap, char*); if( z2==0 ) z2 = zNull; len = strlen(z2); memcpy(z, z2, len); z += len; if( zFormat[i]=='z' && z2!=zNull ){ sqliteFree(z2); } break; } case 'T': { Token *p = va_arg(ap, Token*); memcpy(z, p->z, p->n); z += p->n; break; } case 'S': { int len; SrcList *p = va_arg(ap, SrcList*); int k = va_arg(ap, int); assert( p->nSrc>k && k>=0 ); if( p->a[k].zDatabase && p->a[k].zDatabase[0] ){ len = strlen(p->a[k].zDatabase); memcpy(z, p->a[k].zDatabase, len); z += len; *(z++) = '.'; } len = strlen(p->a[k].zName); memcpy(z, p->a[k].zName, len); z += len; break; } default: { *(z++) = zFormat[i]; break; } } } va_end(ap); if( i>j ){ memcpy(z, &zFormat[j], i-j); z += i-j; } assert( (z - pParse->zErrMsg) < nByte ); *z = 0;}/*** Convert an SQL-style quoted string into a normal string by removing** the quote characters. The conversion is done in-place. If the** input does not begin with a quote character, then this routine** is a no-op.**** 2002-Feb-14: This routine is extended to remove MS-Access style** brackets from around identifers. For example: "[a-b-c]" becomes** "a-b-c".*/void sqliteDequote(char *z){ int quote; int i, j; if( z==0 ) return; quote = z[0]; switch( quote ){ case '\'': break; case '"': break; case '[': quote = ']'; break; default: return; } for(i=1, j=0; z[i]; i++){ if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; i++; }else{ z[j++] = 0; break; } }else{ z[j++] = z[i]; } }}/* 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; if( n<=0 ) n = strlen(z); while( n > 0 ){ h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++]; n--; } return h & 0x7fffffff;}/*** Some systems have 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;}/*** Return TRUE if z is a pure numeric string. Return FALSE if the** string contains any character which is not part of a number.**** Am empty string is considered non-numeric.*/int sqliteIsNumber(const char *z){ if( *z=='-' || *z=='+' ) z++; if( !isdigit(*z) ){ return 0; } z++; while( isdigit(*z) ){ z++; } if( *z=='.' ){ z++; if( !isdigit(*z) ) return 0; while( isdigit(*z) ){ z++; } } if( *z=='e' || *z=='E' ){ z++; if( *z=='+' || *z=='-' ) z++; if( !isdigit(*z) ) return 0; while( isdigit(*z) ){ z++; } } return *z==0;}/* This comparison routine is what we use for comparison operations** between numeric values in an SQL expression. "Numeric" is a little** bit misleading here. What we mean is that the strings have a** type of "numeric" from the point of view of SQL. The strings** do not necessarily contain numbers. They could contain text.**** If the input strings both look like actual numbers then they** compare in numerical order. Numerical strings are always less ** than non-numeric strings so if one input string looks like a** number and the other does not, then the one that looks like** a number is the smaller. Non-numeric strings compare in ** lexigraphical order (the same order as strcmp()).*/int sqliteCompare(const char *atext, const char *btext){ int result; int isNumA, isNumB; if( atext==0 ){ return -1; }else if( btext==0 ){ return 1; } isNumA = sqliteIsNumber(atext); isNumB = sqliteIsNumber(btext); if( isNumA ){ if( !isNumB ){ result = -1; }else{ double rA, rB; rA = atof(atext); rB = atof(btext); if( rA<rB ){ result = -1; }else if( rA>rB ){ result = +1; }else{ result = 0; } } }else if( isNumB ){ result = +1; }else { result = strcmp(atext, btext); } return result; }/*** This routine is used for sorting. Each key is a list of one or more** null-terminated elements. The list is terminated by two nulls in** a row. For example, the following text is a key with three elements**** Aone\000Dtwo\000Athree\000\000**** All elements begin with one of the characters "+-AD" and end with "\000"** with zero or more text elements in between. Except, NULL elements** consist of the special two-character sequence "N\000".**** Both arguments will have the same number of elements. 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).**** Each element begins with one of the characters "+", "-", "A", "D".** This character determines the sort order and collating sequence:**** + Sort numerically in ascending order** - Sort numerically in descending order** A Sort as strings in ascending order** D Sort as strings in descending order.**** For the "+" and "-" sorting, pure numeric strings (strings for which the** isNum() function above returns TRUE) always compare less than strings** that are not pure numerics. Non-numeric strings compare in memcmp()** order. This is the same sort order as the sqliteCompare() function** above generates.**** The last point is a change from version 2.6.3 to version 2.7.0. In** version 2.6.3 and earlier, substrings of digits compare in numerical ** and case was used only to break a tie.**** Elements that begin with 'A' or 'D' compare in memcmp() order regardless** of whether or not they look like a number.**** Note that the sort order imposed by the rules above is the same** from the ordering defined by the "<", "<=", ">", and ">=" operators** of expressions and for indices. This was not the case for version** 2.6.3 and earlier.*/int sqliteSortCompare(const char *a, const char *b){ int res = 0; int isNumA, isNumB; int dir = 0; while( res==0 && *a && *b ){ if( a[0]=='N' || b[0]=='N' ){ if( a[0]==b[0] ){ a += 2; b += 2; continue; } if( a[0]=='N' ){ dir = b[0]; res = -1; }else{ dir = a[0]; res = +1; } break; } assert( a[0]==b[0] ); if( (dir=a[0])=='A' || a[0]=='D' ){ res = strcmp(&a[1],&b[1]); if( res ) break; }else{ isNumA = sqliteIsNumber(&a[1]); isNumB = sqliteIsNumber(&b[1]); if( isNumA ){ double rA, rB; if( !isNumB ){ res = -1; break; } rA = atof(&a[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -