Index: third_party/sqlite/src/src/printf.c |
diff --git a/third_party/sqlite/src/src/printf.c b/third_party/sqlite/src/src/printf.c |
index 2a3dd81d7d2603a072d5074973004ab48123bc7f..387b9e90c18e241a983095429b235d0b2d95f1ec 100644 |
--- a/third_party/sqlite/src/src/printf.c |
+++ b/third_party/sqlite/src/src/printf.c |
@@ -7,52 +7,25 @@ |
** |
************************************************************************** |
** |
-** The following modules is an enhanced replacement for the "printf" subroutines |
-** found in the standard C library. The following enhancements are |
-** supported: |
-** |
-** + Additional functions. The standard set of "printf" functions |
-** includes printf, fprintf, sprintf, vprintf, vfprintf, and |
-** vsprintf. This module adds the following: |
-** |
-** * snprintf -- Works like sprintf, but has an extra argument |
-** which is the size of the buffer written to. |
-** |
-** * mprintf -- Similar to sprintf. Writes output to memory |
-** obtained from malloc. |
-** |
-** * xprintf -- Calls a function to dispose of output. |
-** |
-** * nprintf -- No output, but returns the number of characters |
-** that would have been output by printf. |
-** |
-** * A v- version (ex: vsnprintf) of every function is also |
-** supplied. |
-** |
-** + A few extensions to the formatting notation are supported: |
-** |
-** * The "=" flag (similar to "-") causes the output to be |
-** be centered in the appropriately sized field. |
-** |
-** * The %b field outputs an integer in binary notation. |
-** |
-** * The %c field now accepts a precision. The character output |
-** is repeated by the number of times the precision specifies. |
-** |
-** * The %' field works like %c, but takes as its character the |
-** next character of the format string, instead of the next |
-** argument. For example, printf("%.78'-") prints 78 minus |
-** signs, the same as printf("%.78c",'-'). |
-** |
-** + When compiled using GCC on a SPARC, this version of printf is |
-** faster than the library printf for SUN OS 4.1. |
-** |
-** + All functions are fully reentrant. |
-** |
+** This file contains code for a set of "printf"-like routines. These |
+** routines format strings much like the printf() from the standard C |
+** library, though the implementation here has enhancements to support |
+** SQLlite. |
*/ |
#include "sqliteInt.h" |
/* |
+** If the strchrnul() library function is available, then set |
+** HAVE_STRCHRNUL. If that routine is not available, this module |
+** will supply its own. The built-in version is slower than |
+** the glibc version so the glibc version is definitely preferred. |
+*/ |
+#if !defined(HAVE_STRCHRNUL) |
+# define HAVE_STRCHRNUL 0 |
+#endif |
+ |
+ |
+/* |
** Conversion types fall into various categories as defined by the |
** following enumeration. |
*/ |
@@ -162,7 +135,8 @@ static const et_info fmtinfo[] = { |
static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ |
int digit; |
LONGDOUBLE_TYPE d; |
- if( (*cnt)++ >= 16 ) return '0'; |
+ if( (*cnt)<=0 ) return '0'; |
+ (*cnt)--; |
digit = (int)*val; |
d = digit; |
digit += '0'; |
@@ -172,64 +146,47 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ |
#endif /* SQLITE_OMIT_FLOATING_POINT */ |
/* |
-** Append N space characters to the given string buffer. |
+** Set the StrAccum object to an error mode. |
*/ |
-static void appendSpace(StrAccum *pAccum, int N){ |
- static const char zSpaces[] = " "; |
- while( N>=(int)sizeof(zSpaces)-1 ){ |
- sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1); |
- N -= sizeof(zSpaces)-1; |
- } |
- if( N>0 ){ |
- sqlite3StrAccumAppend(pAccum, zSpaces, N); |
- } |
+static void setStrAccumError(StrAccum *p, u8 eError){ |
+ p->accError = eError; |
+ p->nAlloc = 0; |
+} |
+ |
+/* |
+** Extra argument values from a PrintfArguments object |
+*/ |
+static sqlite3_int64 getIntArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0; |
+ return sqlite3_value_int64(p->apArg[p->nUsed++]); |
+} |
+static double getDoubleArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0.0; |
+ return sqlite3_value_double(p->apArg[p->nUsed++]); |
} |
+static char *getTextArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0; |
+ return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); |
+} |
+ |
/* |
** On machines with a small stack size, you can redefine the |
-** SQLITE_PRINT_BUF_SIZE to be less than 350. |
+** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. |
*/ |
#ifndef SQLITE_PRINT_BUF_SIZE |
-# if defined(SQLITE_SMALL_STACK) |
-# define SQLITE_PRINT_BUF_SIZE 50 |
-# else |
-# define SQLITE_PRINT_BUF_SIZE 350 |
-# endif |
+# define SQLITE_PRINT_BUF_SIZE 70 |
#endif |
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ |
/* |
-** The root program. All variations call this core. |
-** |
-** INPUTS: |
-** func This is a pointer to a function taking three arguments |
-** 1. A pointer to anything. Same as the "arg" parameter. |
-** 2. A pointer to the list of characters to be output |
-** (Note, this list is NOT null terminated.) |
-** 3. An integer number of characters to be output. |
-** (Note: This number might be zero.) |
-** |
-** arg This is the pointer to anything which will be passed as the |
-** first argument to "func". Use it for whatever you like. |
-** |
-** fmt This is the format string, as in the usual print. |
-** |
-** ap This is a pointer to a list of arguments. Same as in |
-** vfprint. |
-** |
-** OUTPUTS: |
-** The return value is the total number of characters sent to |
-** the function "func". Returns -1 on a error. |
-** |
-** Note that the order in which automatic variables are declared below |
-** seems to make a big difference in determining how fast this beast |
-** will run. |
+** Render a string given by "fmt" into the StrAccum object. |
*/ |
void sqlite3VXPrintf( |
- StrAccum *pAccum, /* Accumulate results here */ |
- int useExtended, /* Allow extended %-conversions */ |
- const char *fmt, /* Format string */ |
- va_list ap /* arguments */ |
+ StrAccum *pAccum, /* Accumulate results here */ |
+ u32 bFlags, /* SQLITE_PRINTF_* flags */ |
+ const char *fmt, /* Format string */ |
+ va_list ap /* arguments */ |
){ |
int c; /* Next character in the format string */ |
char *bufpt; /* Pointer to the conversion buffer */ |
@@ -246,32 +203,45 @@ void sqlite3VXPrintf( |
etByte flag_long; /* True if "l" flag is present */ |
etByte flag_longlong; /* True if the "ll" flag is present */ |
etByte done; /* Loop termination flag */ |
+ etByte xtype = 0; /* Conversion paradigm */ |
+ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ |
+ u8 useIntern; /* Ok to use internal conversions (ex: %T) */ |
+ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ |
sqlite_uint64 longvalue; /* Value for integer types */ |
LONGDOUBLE_TYPE realvalue; /* Value for real types */ |
const et_info *infop; /* Pointer to the appropriate info structure */ |
- char buf[etBUFSIZE]; /* Conversion buffer */ |
- char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ |
- etByte xtype = 0; /* Conversion paradigm */ |
- char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ |
+ char *zOut; /* Rendering buffer */ |
+ int nOut; /* Size of the rendering buffer */ |
+ char *zExtra = 0; /* Malloced memory used by some conversion */ |
#ifndef SQLITE_OMIT_FLOATING_POINT |
int exp, e2; /* exponent of real numbers */ |
+ int nsd; /* Number of significant digits returned */ |
double rounder; /* Used for rounding floating point values */ |
etByte flag_dp; /* True if decimal point should be shown */ |
etByte flag_rtz; /* True if trailing zeros should be removed */ |
- etByte flag_exp; /* True to force display of the exponent */ |
- int nsd; /* Number of significant digits returned */ |
#endif |
+ PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ |
+ char buf[etBUFSIZE]; /* Conversion buffer */ |
- length = 0; |
bufpt = 0; |
+ if( bFlags ){ |
+ if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){ |
+ pArgList = va_arg(ap, PrintfArguments*); |
+ } |
+ useIntern = bFlags & SQLITE_PRINTF_INTERNAL; |
+ }else{ |
+ bArgList = useIntern = 0; |
+ } |
for(; (c=(*fmt))!=0; ++fmt){ |
if( c!='%' ){ |
- int amt; |
bufpt = (char *)fmt; |
- amt = 1; |
- while( (c=(*++fmt))!='%' && c!=0 ) amt++; |
- sqlite3StrAccumAppend(pAccum, bufpt, amt); |
- if( c==0 ) break; |
+#if HAVE_STRCHRNUL |
+ fmt = strchrnul(fmt, '%'); |
+#else |
+ do{ fmt++; }while( *fmt && *fmt != '%' ); |
+#endif |
+ sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); |
+ if( *fmt==0 ) break; |
} |
if( (c=(*++fmt))==0 ){ |
sqlite3StrAccumAppend(pAccum, "%", 1); |
@@ -295,7 +265,11 @@ void sqlite3VXPrintf( |
/* Get the field width */ |
width = 0; |
if( c=='*' ){ |
- width = va_arg(ap,int); |
+ if( bArgList ){ |
+ width = (int)getIntArg(pArgList); |
+ }else{ |
+ width = va_arg(ap,int); |
+ } |
if( width<0 ){ |
flag_leftjustify = 1; |
width = -width; |
@@ -307,15 +281,16 @@ void sqlite3VXPrintf( |
c = *++fmt; |
} |
} |
- if( width > etBUFSIZE-10 ){ |
- width = etBUFSIZE-10; |
- } |
/* Get the precision */ |
if( c=='.' ){ |
precision = 0; |
c = *++fmt; |
if( c=='*' ){ |
- precision = va_arg(ap,int); |
+ if( bArgList ){ |
+ precision = (int)getIntArg(pArgList); |
+ }else{ |
+ precision = va_arg(ap,int); |
+ } |
if( precision<0 ) precision = -precision; |
c = *++fmt; |
}else{ |
@@ -346,7 +321,7 @@ void sqlite3VXPrintf( |
for(idx=0; idx<ArraySize(fmtinfo); idx++){ |
if( c==fmtinfo[idx].fmttype ){ |
infop = &fmtinfo[idx]; |
- if( useExtended || (infop->flags & FLAG_INTERN)==0 ){ |
+ if( useIntern || (infop->flags & FLAG_INTERN)==0 ){ |
xtype = infop->type; |
}else{ |
return; |
@@ -354,13 +329,6 @@ void sqlite3VXPrintf( |
break; |
} |
} |
- zExtra = 0; |
- |
- |
- /* Limit the precision to prevent overflowing buf[] during conversion */ |
- if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ |
- precision = etBUFSIZE-40; |
- } |
/* |
** At this point, variables are initialized as follows: |
@@ -392,7 +360,9 @@ void sqlite3VXPrintf( |
case etRADIX: |
if( infop->flags & FLAG_SIGNED ){ |
i64 v; |
- if( flag_longlong ){ |
+ if( bArgList ){ |
+ v = getIntArg(pArgList); |
+ }else if( flag_longlong ){ |
v = va_arg(ap,i64); |
}else if( flag_long ){ |
v = va_arg(ap,long int); |
@@ -413,7 +383,9 @@ void sqlite3VXPrintf( |
else prefix = 0; |
} |
}else{ |
- if( flag_longlong ){ |
+ if( bArgList ){ |
+ longvalue = (u64)getIntArg(pArgList); |
+ }else if( flag_longlong ){ |
longvalue = va_arg(ap,u64); |
}else if( flag_long ){ |
longvalue = va_arg(ap,unsigned long int); |
@@ -426,28 +398,36 @@ void sqlite3VXPrintf( |
if( flag_zeropad && precision<width-(prefix!=0) ){ |
precision = width-(prefix!=0); |
} |
- bufpt = &buf[etBUFSIZE-1]; |
+ if( precision<etBUFSIZE-10 ){ |
+ nOut = etBUFSIZE; |
+ zOut = buf; |
+ }else{ |
+ nOut = precision + 10; |
+ zOut = zExtra = sqlite3Malloc( nOut ); |
+ if( zOut==0 ){ |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
+ return; |
+ } |
+ } |
+ bufpt = &zOut[nOut-1]; |
if( xtype==etORDINAL ){ |
static const char zOrd[] = "thstndrd"; |
int x = (int)(longvalue % 10); |
if( x>=4 || (longvalue/10)%10==1 ){ |
x = 0; |
} |
- buf[etBUFSIZE-3] = zOrd[x*2]; |
- buf[etBUFSIZE-2] = zOrd[x*2+1]; |
- bufpt -= 2; |
+ *(--bufpt) = zOrd[x*2+1]; |
+ *(--bufpt) = zOrd[x*2]; |
} |
{ |
- register const char *cset; /* Use registers for speed */ |
- register int base; |
- cset = &aDigits[infop->charset]; |
- base = infop->base; |
+ const char *cset = &aDigits[infop->charset]; |
+ u8 base = infop->base; |
do{ /* Convert to ascii */ |
*(--bufpt) = cset[longvalue%base]; |
longvalue = longvalue/base; |
}while( longvalue>0 ); |
} |
- length = (int)(&buf[etBUFSIZE-1]-bufpt); |
+ length = (int)(&zOut[nOut-1]-bufpt); |
for(idx=precision-length; idx>0; idx--){ |
*(--bufpt) = '0'; /* Zero pad */ |
} |
@@ -458,17 +438,20 @@ void sqlite3VXPrintf( |
pre = &aPrefix[infop->prefix]; |
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; |
} |
- length = (int)(&buf[etBUFSIZE-1]-bufpt); |
+ length = (int)(&zOut[nOut-1]-bufpt); |
break; |
case etFLOAT: |
case etEXP: |
case etGENERIC: |
- realvalue = va_arg(ap,double); |
+ if( bArgList ){ |
+ realvalue = getDoubleArg(pArgList); |
+ }else{ |
+ realvalue = va_arg(ap,double); |
+ } |
#ifdef SQLITE_OMIT_FLOATING_POINT |
length = 0; |
#else |
if( precision<0 ) precision = 6; /* Set default precision */ |
- if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10; |
if( realvalue<0.0 ){ |
realvalue = -realvalue; |
prefix = '-'; |
@@ -478,13 +461,7 @@ void sqlite3VXPrintf( |
else prefix = 0; |
} |
if( xtype==etGENERIC && precision>0 ) precision--; |
-#if 0 |
- /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ |
- for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); |
-#else |
- /* It makes more sense to use 0.5 */ |
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){} |
-#endif |
if( xtype==etFLOAT ) realvalue += rounder; |
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ |
exp = 0; |
@@ -494,9 +471,12 @@ void sqlite3VXPrintf( |
break; |
} |
if( realvalue>0.0 ){ |
- while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } |
- while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } |
- while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } |
+ LONGDOUBLE_TYPE scale = 1.0; |
+ while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} |
+ while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; } |
+ while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; } |
+ while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } |
+ realvalue /= scale; |
while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } |
while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } |
if( exp>350 ){ |
@@ -516,7 +496,6 @@ void sqlite3VXPrintf( |
** If the field type is etGENERIC, then convert to either etEXP |
** or etFLOAT, as appropriate. |
*/ |
- flag_exp = xtype==etEXP; |
if( xtype!=etFLOAT ){ |
realvalue += rounder; |
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } |
@@ -530,14 +509,22 @@ void sqlite3VXPrintf( |
xtype = etFLOAT; |
} |
}else{ |
- flag_rtz = 0; |
+ flag_rtz = flag_altform2; |
} |
if( xtype==etEXP ){ |
e2 = 0; |
}else{ |
e2 = exp; |
} |
- nsd = 0; |
+ if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){ |
+ bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 ); |
+ if( bufpt==0 ){ |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
+ return; |
+ } |
+ } |
+ zOut = bufpt; |
+ nsd = 16 + flag_altform2*10; |
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; |
/* The sign in front of the number */ |
if( prefix ){ |
@@ -568,7 +555,7 @@ void sqlite3VXPrintf( |
/* Remove trailing zeros and the "." if no digits follow the "." */ |
if( flag_rtz && flag_dp ){ |
while( bufpt[-1]=='0' ) *(--bufpt) = 0; |
- assert( bufpt>buf ); |
+ assert( bufpt>zOut ); |
if( bufpt[-1]=='.' ){ |
if( flag_altform2 ){ |
*(bufpt++) = '0'; |
@@ -578,7 +565,7 @@ void sqlite3VXPrintf( |
} |
} |
/* Add the "eNNN" suffix */ |
- if( flag_exp || xtype==etEXP ){ |
+ if( xtype==etEXP ){ |
*(bufpt++) = aDigits[infop->charset]; |
if( exp<0 ){ |
*(bufpt++) = '-'; exp = -exp; |
@@ -597,8 +584,8 @@ void sqlite3VXPrintf( |
/* The converted number is in buf[] and zero terminated. Output it. |
** Note that the number is in the usual order, not reversed as with |
** integer conversions. */ |
- length = (int)(bufpt-buf); |
- bufpt = buf; |
+ length = (int)(bufpt-zOut); |
+ bufpt = zOut; |
/* Special case: Add leading zeros if the flag_zeropad flag is |
** set and we are not left justified */ |
@@ -615,7 +602,9 @@ void sqlite3VXPrintf( |
#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */ |
break; |
case etSIZE: |
- *(va_arg(ap,int*)) = pAccum->nChar; |
+ if( !bArgList ){ |
+ *(va_arg(ap,int*)) = pAccum->nChar; |
+ } |
length = width = 0; |
break; |
case etPERCENT: |
@@ -624,22 +613,34 @@ void sqlite3VXPrintf( |
length = 1; |
break; |
case etCHARX: |
- c = va_arg(ap,int); |
- buf[0] = (char)c; |
- if( precision>=0 ){ |
- for(idx=1; idx<precision; idx++) buf[idx] = (char)c; |
- length = precision; |
+ if( bArgList ){ |
+ bufpt = getTextArg(pArgList); |
+ c = bufpt ? bufpt[0] : 0; |
}else{ |
- length =1; |
+ c = va_arg(ap,int); |
} |
+ if( precision>1 ){ |
+ width -= precision-1; |
+ if( width>1 && !flag_leftjustify ){ |
+ sqlite3AppendChar(pAccum, width-1, ' '); |
+ width = 0; |
+ } |
+ sqlite3AppendChar(pAccum, precision-1, c); |
+ } |
+ length = 1; |
+ buf[0] = c; |
bufpt = buf; |
break; |
case etSTRING: |
case etDYNSTRING: |
- bufpt = va_arg(ap,char*); |
+ if( bArgList ){ |
+ bufpt = getTextArg(pArgList); |
+ }else{ |
+ bufpt = va_arg(ap,char*); |
+ } |
if( bufpt==0 ){ |
bufpt = ""; |
- }else if( xtype==etDYNSTRING ){ |
+ }else if( xtype==etDYNSTRING && !bArgList ){ |
zExtra = bufpt; |
} |
if( precision>=0 ){ |
@@ -655,7 +656,13 @@ void sqlite3VXPrintf( |
int needQuote; |
char ch; |
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ |
- char *escarg = va_arg(ap,char*); |
+ char *escarg; |
+ |
+ if( bArgList ){ |
+ escarg = getTextArg(pArgList); |
+ }else{ |
+ escarg = va_arg(ap,char*); |
+ } |
isnull = escarg==0; |
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); |
k = precision; |
@@ -667,7 +674,7 @@ void sqlite3VXPrintf( |
if( n>etBUFSIZE ){ |
bufpt = zExtra = sqlite3Malloc( n ); |
if( bufpt==0 ){ |
- pAccum->mallocFailed = 1; |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
return; |
} |
}else{ |
@@ -690,7 +697,8 @@ void sqlite3VXPrintf( |
} |
case etTOKEN: { |
Token *pToken = va_arg(ap, Token*); |
- if( pToken ){ |
+ assert( bArgList==0 ); |
+ if( pToken && pToken->n ){ |
sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); |
} |
length = width = 0; |
@@ -700,12 +708,13 @@ void sqlite3VXPrintf( |
SrcList *pSrc = va_arg(ap, SrcList*); |
int k = va_arg(ap, int); |
struct SrcList_item *pItem = &pSrc->a[k]; |
+ assert( bArgList==0 ); |
assert( k>=0 && k<pSrc->nSrc ); |
if( pItem->zDatabase ){ |
- sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1); |
+ sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase); |
sqlite3StrAccumAppend(pAccum, ".", 1); |
} |
- sqlite3StrAccumAppend(pAccum, pItem->zName, -1); |
+ sqlite3StrAccumAppendAll(pAccum, pItem->zName); |
length = width = 0; |
break; |
} |
@@ -719,84 +728,117 @@ void sqlite3VXPrintf( |
** "length" characters long. The field width is "width". Do |
** the output. |
*/ |
- if( !flag_leftjustify ){ |
- register int nspace; |
- nspace = width-length; |
- if( nspace>0 ){ |
- appendSpace(pAccum, nspace); |
- } |
- } |
- if( length>0 ){ |
- sqlite3StrAccumAppend(pAccum, bufpt, length); |
- } |
- if( flag_leftjustify ){ |
- register int nspace; |
- nspace = width-length; |
- if( nspace>0 ){ |
- appendSpace(pAccum, nspace); |
- } |
- } |
+ width -= length; |
+ if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); |
+ sqlite3StrAccumAppend(pAccum, bufpt, length); |
+ if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); |
+ |
if( zExtra ){ |
sqlite3_free(zExtra); |
+ zExtra = 0; |
} |
}/* End for loop over the format string */ |
} /* End of function */ |
/* |
-** Append N bytes of text from z to the StrAccum object. |
+** Enlarge the memory allocation on a StrAccum object so that it is |
+** able to accept at least N more bytes of text. |
+** |
+** Return the number of bytes of text that StrAccum is able to accept |
+** after the attempted enlargement. The value returned might be zero. |
*/ |
-void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ |
- assert( z!=0 || N==0 ); |
- if( p->tooBig | p->mallocFailed ){ |
- testcase(p->tooBig); |
- testcase(p->mallocFailed); |
- return; |
+static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ |
+ char *zNew; |
+ assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ |
+ if( p->accError ){ |
+ testcase(p->accError==STRACCUM_TOOBIG); |
+ testcase(p->accError==STRACCUM_NOMEM); |
+ return 0; |
} |
- if( N<0 ){ |
- N = sqlite3Strlen30(z); |
+ if( !p->useMalloc ){ |
+ N = p->nAlloc - p->nChar - 1; |
+ setStrAccumError(p, STRACCUM_TOOBIG); |
+ return N; |
+ }else{ |
+ char *zOld = (p->zText==p->zBase ? 0 : p->zText); |
+ i64 szNew = p->nChar; |
+ szNew += N + 1; |
+ if( szNew > p->mxAlloc ){ |
+ sqlite3StrAccumReset(p); |
+ setStrAccumError(p, STRACCUM_TOOBIG); |
+ return 0; |
+ }else{ |
+ p->nAlloc = (int)szNew; |
+ } |
+ if( p->useMalloc==1 ){ |
+ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); |
+ }else{ |
+ zNew = sqlite3_realloc(zOld, p->nAlloc); |
+ } |
+ if( zNew ){ |
+ assert( p->zText!=0 || p->nChar==0 ); |
+ if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); |
+ p->zText = zNew; |
+ }else{ |
+ sqlite3StrAccumReset(p); |
+ setStrAccumError(p, STRACCUM_NOMEM); |
+ return 0; |
+ } |
} |
- if( N==0 || NEVER(z==0) ){ |
- return; |
+ return N; |
+} |
+ |
+/* |
+** Append N copies of character c to the given string buffer. |
+*/ |
+void sqlite3AppendChar(StrAccum *p, int N, char c){ |
+ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; |
+ while( (N--)>0 ) p->zText[p->nChar++] = c; |
+} |
+ |
+/* |
+** The StrAccum "p" is not large enough to accept N new bytes of z[]. |
+** So enlarge if first, then do the append. |
+** |
+** This is a helper routine to sqlite3StrAccumAppend() that does special-case |
+** work (enlarging the buffer) using tail recursion, so that the |
+** sqlite3StrAccumAppend() routine can use fast calling semantics. |
+*/ |
+static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ |
+ N = sqlite3StrAccumEnlarge(p, N); |
+ if( N>0 ){ |
+ memcpy(&p->zText[p->nChar], z, N); |
+ p->nChar += N; |
} |
+} |
+ |
+/* |
+** Append N bytes of text from z to the StrAccum object. Increase the |
+** size of the memory allocation for StrAccum if necessary. |
+*/ |
+void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ |
+ assert( z!=0 ); |
+ assert( p->zText!=0 || p->nChar==0 || p->accError ); |
+ assert( N>=0 ); |
+ assert( p->accError==0 || p->nAlloc==0 ); |
if( p->nChar+N >= p->nAlloc ){ |
- char *zNew; |
- if( !p->useMalloc ){ |
- p->tooBig = 1; |
- N = p->nAlloc - p->nChar - 1; |
- if( N<=0 ){ |
- return; |
- } |
- }else{ |
- char *zOld = (p->zText==p->zBase ? 0 : p->zText); |
- i64 szNew = p->nChar; |
- szNew += N + 1; |
- if( szNew > p->mxAlloc ){ |
- sqlite3StrAccumReset(p); |
- p->tooBig = 1; |
- return; |
- }else{ |
- p->nAlloc = (int)szNew; |
- } |
- if( p->useMalloc==1 ){ |
- zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); |
- }else{ |
- zNew = sqlite3_realloc(zOld, p->nAlloc); |
- } |
- if( zNew ){ |
- if( zOld==0 ) memcpy(zNew, p->zText, p->nChar); |
- p->zText = zNew; |
- }else{ |
- p->mallocFailed = 1; |
- sqlite3StrAccumReset(p); |
- return; |
- } |
- } |
+ enlargeAndAppend(p,z,N); |
+ }else{ |
+ assert( p->zText ); |
+ p->nChar += N; |
+ memcpy(&p->zText[p->nChar-N], z, N); |
} |
- memcpy(&p->zText[p->nChar], z, N); |
- p->nChar += N; |
} |
/* |
+** Append the complete text of zero-terminated string z[] to the p string. |
+*/ |
+void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ |
+ sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z)); |
+} |
+ |
+ |
+/* |
** Finish off a string by making sure it is zero-terminated. |
** Return a pointer to the resulting string. Return a NULL |
** pointer if any kind of error was encountered. |
@@ -813,7 +855,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){ |
if( p->zText ){ |
memcpy(p->zText, p->zBase, p->nChar+1); |
}else{ |
- p->mallocFailed = 1; |
+ setStrAccumError(p, STRACCUM_NOMEM); |
} |
} |
} |
@@ -844,8 +886,7 @@ void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){ |
p->nAlloc = n; |
p->mxAlloc = mx; |
p->useMalloc = 1; |
- p->tooBig = 0; |
- p->mallocFailed = 0; |
+ p->accError = 0; |
} |
/* |
@@ -860,9 +901,9 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ |
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), |
db->aLimit[SQLITE_LIMIT_LENGTH]); |
acc.db = db; |
- sqlite3VXPrintf(&acc, 1, zFormat, ap); |
+ sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap); |
z = sqlite3StrAccumFinish(&acc); |
- if( acc.mallocFailed ){ |
+ if( acc.accError==STRACCUM_NOMEM ){ |
db->mallocFailed = 1; |
} |
return z; |
@@ -883,7 +924,7 @@ char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ |
/* |
** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting |
-** the string and before returnning. This routine is intended to be used |
+** the string and before returning. This routine is intended to be used |
** to modify an existing string. For example: |
** |
** x = sqlite3MPrintf(db, x, "prefix %s suffix", x); |
@@ -1016,14 +1057,75 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ |
} |
#endif |
-#ifndef SQLITE_OMIT_TRACE |
+#ifdef SQLITE_DEBUG |
+/************************************************************************* |
+** Routines for implementing the "TreeView" display of hierarchical |
+** data structures for debugging. |
+** |
+** The main entry points (coded elsewhere) are: |
+** sqlite3TreeViewExpr(0, pExpr, 0); |
+** sqlite3TreeViewExprList(0, pList, 0, 0); |
+** sqlite3TreeViewSelect(0, pSelect, 0); |
+** Insert calls to those routines while debugging in order to display |
+** a diagram of Expr, ExprList, and Select objects. |
+** |
+*/ |
+/* Add a new subitem to the tree. The moreToFollow flag indicates that this |
+** is not the last item in the tree. */ |
+TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ |
+ if( p==0 ){ |
+ p = sqlite3_malloc( sizeof(*p) ); |
+ if( p==0 ) return 0; |
+ memset(p, 0, sizeof(*p)); |
+ }else{ |
+ p->iLevel++; |
+ } |
+ assert( moreToFollow==0 || moreToFollow==1 ); |
+ if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; |
+ return p; |
+} |
+/* Finished with one layer of the tree */ |
+void sqlite3TreeViewPop(TreeView *p){ |
+ if( p==0 ) return; |
+ p->iLevel--; |
+ if( p->iLevel<0 ) sqlite3_free(p); |
+} |
+/* Generate a single line of output for the tree, with a prefix that contains |
+** all the appropriate tree lines */ |
+void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ |
+ va_list ap; |
+ int i; |
+ StrAccum acc; |
+ char zBuf[500]; |
+ sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); |
+ acc.useMalloc = 0; |
+ if( p ){ |
+ for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ |
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); |
+ } |
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); |
+ } |
+ va_start(ap, zFormat); |
+ sqlite3VXPrintf(&acc, 0, zFormat, ap); |
+ va_end(ap); |
+ if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); |
+ sqlite3StrAccumFinish(&acc); |
+ fprintf(stdout,"%s", zBuf); |
+ fflush(stdout); |
+} |
+/* Shorthand for starting a new tree item that consists of a single label */ |
+void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){ |
+ p = sqlite3TreeViewPush(p, moreToFollow); |
+ sqlite3TreeViewLine(p, "%s", zLabel); |
+} |
+#endif /* SQLITE_DEBUG */ |
+ |
/* |
** variable-argument wrapper around sqlite3VXPrintf(). |
*/ |
-void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ |
+void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){ |
va_list ap; |
va_start(ap,zFormat); |
- sqlite3VXPrintf(p, 1, zFormat, ap); |
+ sqlite3VXPrintf(p, bFlags, zFormat, ap); |
va_end(ap); |
} |
-#endif |