📄 util.c
字号:
#include "eDbInit.h"
/*
** Number of 32-bit guard words
*/
#define N_GUARD 1
int eDb_malloc_failed = 0;
/*
** Allocate new memory and set it to zero. Return NULL if
** no memory is available. See also eDbMallocRaw().
*/
long nMalloc = 0;
void *eDbMalloc(int n){
void *p;
if( (p = _MALLOC_(n))==0 ){
if( n>0 ) eDb_malloc_failed++;
}else{
memset(p, 0, n);
//fprintf(fdebug,"M %d:--%x\t",++nMalloc,p);
}
return p;
}
/*
** Allocate new memory but do not set it to zero. Return NULL if
** no memory is available. See also eDbMalloc().
*/
void *eDbMallocRaw(int n){
void *p;
if( (p = _MALLOC_(n))==0 ){
if( n>0 ) eDb_malloc_failed++;
}else{
//fprintf(fdebug,"MR%d:--%x\t",++nMalloc,p);
}
return p;
}
/*
** Free memory previously obtained from eDbMalloc()
*/
long nFree = 0;
void eDbFree(void *p){
if( p ){
_FREE_(p);
//fprintf(fdebug,"F %d:--%x\t",++nFree,p);
}
}
/*
** Resize a prior allocation. If p==0, then this routine
** works just like eDbMalloc(). If n==0, then this routine
** works just like eDbFree().
*/
void *eDbRealloc(void *p, int n){
void *p2;
if( p==0 ){
return eDbMalloc(n);
}
if( n==0 ){
eDbFree(p);
return 0;
}
p2 = _REALLOC_(p, n);
if( p2==0 ){
eDb_malloc_failed++;
}else{
//fprintf(fdebug,"MA%d:--%x:%x\t",++nMalloc,p,p2);
}
return p2;
}
/*
** Make a copy of a string in memory obtained from eDbMalloc()
*/
char *eDbStrDup(const char *z){
char *zNew;
if( z==0 ) return 0;
zNew = eDbMallocRaw(strlen(z)+1);
if( zNew ) strcpy(zNew, z);
return zNew;
}
char *eDbStrNDup(const char *z, int n){
char *zNew;
if( z==0 ) return 0;
zNew = eDbMallocRaw(n+1);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
/*
** Check to see if the given pointer was obtained from eDbMalloc()
** and is able to hold at least N bytes. Raise an exception if this
** is not the case.
**
** This routine is used for testing purposes only.
*/
void eDbCheckMemory(void *p, int N){
int *pi = p;
int n, i, k;
pi -= N_GUARD+1;
for(i=0; i<N_GUARD; i++){
assert( pi[i]==0xdead1122 );
}
n = pi[N_GUARD];
assert( N>=0 && N<n );
k = (n+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
assert( pi[k+N_GUARD+1+i]==0xdead3344 );
}
}
/*
** Create a string from the 2nd and subsequent arguments (up to the
** first NULL argument), store the string in memory obtained from
** eDbMalloc() and make the pointer indicated by the 1st argument
** point to that string. The 1st argument must either be NULL or
** point to memory obtained from eDbMalloc().
*/
void eDbSetString(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);
eDbFree(*pz);
*pz = zResult = eDbMallocRaw( 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);
}
/* 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 eDbHashNoCase(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 eDbStrICmp(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 eDbStrNICmp(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;
}
void eDbSetNString(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);
eDbFree(*pz);
*pz = zResult = eDbMallocRaw( 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);
}
void eDbErrorMsg(Parser *pParse, const char *zfmt, ...){
int n,nByte;
int count;
char *bufpt;
const char *z;
char c;
char sbuf[200];
char zInt[12];
va_list ap;
pParse->nErr++;
eDbFree(pParse->zErrMsg);
nByte = 0;
count = 0;
va_start(ap, zfmt);
for(; (c=(*zfmt))!=0; ++zfmt){
if( c!='%' ){
int amt;
bufpt = (char *)zfmt;
amt = 1;
while( (c=(*++zfmt))!='%' && c!=0 ) amt++;
memcpy(&sbuf[count],bufpt,amt);
count += amt;
if( c==0 ) break;
}
if( c=='%' ){
c = * ++zfmt;
if(c==0) break;
switch(c){
case 'd':{
n = va_arg(ap, int);
itoa(n,zInt,10);
n = strlen(zInt);
strcpy(&sbuf[count],zInt);
count += n;
break;
}
case 's':{
z = va_arg(ap, const char*);
n = strlen(z);
strcpy(&sbuf[count],z);
count += n;
break;
}
}
}
}
va_end(ap);
sbuf[count] = 0;
n = strlen(sbuf);
pParse->zErrMsg = eDbMalloc(n+1);
strcpy(pParse->zErrMsg,sbuf);
fprintf(fout,"%s\n",pParse->zErrMsg);
}
int eDbVdbeByteSwap(int x){
union {
char zBuf[sizeof(int)];
int i;
} ux;
ux.zBuf[3] = x&0xff;
ux.zBuf[2] = (x>>8)&0xff;
ux.zBuf[1] = (x>>16)&0xff;
ux.zBuf[0] = (x>>24)&0xff;
return ux.i;
}
void eDbDequote(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];
}
}
}
void eDbFreeKayData(KeyData *p){
eDbFree(p->pKey);
eDbFree(p->pData);
eDbFree(p);
}
void eDbFreeParseResult(ParseResult *p){
if(p == 0) return ;
if( p->pEList ) eDbExprListDelete(p->pEList);
if( p->pSelect ) eDbSelectDelete(p->pSelect);
if( p->pIdList ) eDbIdListDelete(p->pIdList);
if( p->pSrc ) eDbSrcListDelete(p->pSrc);
if( p->pWhere ) eDbExprDelete(p->pWhere);
if(p->zSql) eDbFree(p->zSql);
eDbFree(p);
}
int eDbLookupTupleByIdxKey(BtCursor *pCur,const char *zKey, int nKey, int omit,int op){
int rc,res;
rc = eDbBtreeMoveto(pCur, zKey,strlen(zKey)+1, &res);
if( rc==0 && res >= omit){
eDbBtreeKeyCompare(pCur, zKey, nKey-omit, omit, &res);
}
switch(op){
case TK_LE:
res = res <= 0;
break;
case TK_LT:
res = res < 0;
break;
case TK_GE:
res = res >= 0;
break;
case TK_GT:
res = res > 0;
break;
case TK_NE:
res = res != 0;
break;
case TK_EQ:
res = res == 0;
break;
default:{
res = 0;
}
}
return res;
}
/*
** compare two strings, if they meet to op
** then return true, or else return false;
*/
int eDbStrCompareOK(int op,int type,const char *zSrc,const char *zDes){
int rc;
switch(type){
case eDb_SO_NUM:{
int iSrc = atoi(zSrc);
int iDes = atoi(zDes);
rc = iSrc - iDes;
break;
}
case eDb_SO_DEC:{
break;
}
default:{
rc = eDbStrICmp(zSrc,zDes);
}
}
switch(op){
case TK_LE:
rc = rc <= 0;
break;
case TK_LT:
rc = rc < 0;
break;
case TK_GE:
rc = rc >= 0;
break;
case TK_GT:
rc = rc > 0;
break;
case TK_NE:
rc = rc != 0;
break;
case TK_EQ:
rc = rc == 0;
break;
default:{
rc = 0;
}
}
return rc;
}
/*
** look up the name in table
** if found, return the idx in column
** else return -1
*/
int eDbLookupColName(Table *pTab,const char *name){
int i;
for(i=0;i<pTab->nCol;i++){
if(eDbStrICmp(pTab->aCol[i].zName,name) == 0){
break;
}
}
if(i >= pTab->nCol) i = -1;
return i;
}
/*
** look up i-th column in index
** if found, return the rootpage of the index
** else return 0
*/
int eDbLookupIdxColumn(Table *pTab,int iCol){
int i;
Index *pIdx = pTab->pIndex;
for(;pIdx;pIdx=pIdx->pNext){
for(i=0;i<pIdx->nColumn;i++){
if( i==0 && pIdx->aiColumn[i]==iCol ){
return pIdx->tnum;
}
}
}
return 0;
}
/*
** The string z[] is an ascii representation of a real number.
** Convert this string to a double.
**
** This routine assumes that z[] really is a valid number. If it
** is not, the result is undefined.
**
** This routine is used instead of the library atof() function because
** the library atof() might want to use "," as the decimal point instead
** of "." depending on how locale is set. But that would cause problems
** for SQL. So this routine always uses "." regardless of locale.
*/
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
double eDbAtoF(const char *z, const char **pzEnd){
int sign = 1;
LONGDOUBLE_TYPE v1 = 0.0;
if( *z=='-' ){
sign = -1;
z++;
}else if( *z=='+' ){
z++;
}
while( isdigit(*z) ){
v1 = v1*10.0 + (*z - '0');
z++;
}
if( *z=='.' ){
LONGDOUBLE_TYPE divisor = 1.0;
z++;
while( isdigit(*z) ){
v1 = v1*10.0 + (*z - '0');
divisor *= 10.0;
z++;
}
v1 /= divisor;
}
if( *z=='e' || *z=='E' ){
int esign = 1;
int eval = 0;
LONGDOUBLE_TYPE scale = 1.0;
z++;
if( *z=='-' ){
esign = -1;
z++;
}else if( *z=='+' ){
z++;
}
while( isdigit(*z) ){
eval = eval*10 + *z - '0';
z++;
}
while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
if( esign<0 ){
v1 /= scale;
}else{
v1 *= scale;
}
}
if( pzEnd ) *pzEnd = z;
return sign<0 ? -v1 : v1;
}
/*
** The following procedure converts a double-precision floating point
** number into a string. The resulting string has the property that
** two such strings comparied using strcmp() or memcmp() will give the
** same results as a numeric comparison of the original floating point
** numbers.
**
** This routine is used to generate database keys from floating point
** numbers such that the keys sort in the same order as the original
** floating point numbers even though the keys are compared using
** memcmp().
**
** The calling function should have allocated at least 14 characters
** of space for the buffer z[].
*/
#define _64e3 (64.0 * 64.0 * 64.0)
#define _64e4 (64.0 * 64.0 * 64.0 * 64.0)
#define _64e15 (_64e3 * _64e4 * _64e4 * _64e4)
#define _64e16 (_64e4 * _64e4 * _64e4 * _64e4)
#define _64e63 (_64e15 * _64e16 * _64e16 * _64e16)
#define _64e64 (_64e16 * _64e16 * _64e16 * _64e16)
void eDbRealToSortable(double r, char *z){
int neg;
int exp;
int cnt = 0;
/* This array maps integers between 0 and 63 into base-64 digits.
** The digits must be chosen such at their ASCII codes are increasing.
** This means we can not use the traditional base-64 digit set. */
static const char zDigit[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"|~";
if( r<0.0 ){
neg = 1;
r = -r;
*z++ = '-';
} else {
neg = 0;
*z++ = '0';
}
exp = 0;
if( r==0.0 ){
exp = -1024;
}else if( r<(0.5/64.0) ){
while( r < 0.5/_64e64 && exp > -961 ){ r *= _64e64; exp -= 64; }
while( r < 0.5/_64e16 && exp > -1009 ){ r *= _64e16; exp -= 16; }
while( r < 0.5/_64e4 && exp > -1021 ){ r *= _64e4; exp -= 4; }
while( r < 0.5/64.0 && exp > -1024 ){ r *= 64.0; exp -= 1; }
}else if( r>=0.5 ){
while( r >= 0.5*_64e63 && exp < 960 ){ r *= 1.0/_64e64; exp += 64; }
while( r >= 0.5*_64e15 && exp < 1008 ){ r *= 1.0/_64e16; exp += 16; }
while( r >= 0.5*_64e3 && exp < 1020 ){ r *= 1.0/_64e4; exp += 4; }
while( r >= 0.5 && exp < 1023 ){ r *= 1.0/64.0; exp += 1; }
}
if( neg ){
exp = -exp;
r = -r;
}
exp += 1024;
r += 0.5;
if( exp<0 ) return;
if( exp>=2048 || r>=1.0 ){
strcpy(z, "~~~~~~~~~~~~");
return;
}
*z++ = zDigit[(exp>>6)&0x3f];
*z++ = zDigit[exp & 0x3f];
while( r>0.0 && cnt<10 ){
int digit;
r *= 64.0;
digit = (int)r;
assert( digit>=0 && digit<64 );
*z++ = zDigit[digit & 0x3f];
r -= digit;
cnt++;
}
*z = 0;
}
/*
** The string zNum represents an integer. There might be some other
** information following the integer too, but that part is ignored.
** If the integer that the prefix of zNum represents will fit in a
** 32-bit signed integer, return TRUE. Otherwise return FALSE.
**
** This routine returns FALSE for the string -2147483648 even that
** that number will, in theory fit in a 32-bit integer. But positive
** 2147483648 will not fit in 32 bits. So it seems safer to return
** false.
*/
int eDbFitsIn32Bits(const char *zNum){
int i, c;
if( *zNum=='-' || *zNum=='+' ) zNum++;
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
return i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -