| 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
|
|
|