/*+ −
** The "printf" code that follows dates from the 1980's. It is in+ −
** the public domain. The original comments are included here for+ −
** completeness. They are very out-of-date but might be useful as+ −
** an historical reference. Most of the "enhancements" have been backed+ −
** out so that the functionality is now the same as standard printf().+ −
**+ −
**************************************************************************+ −
**+ −
** 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.+ −
**+ −
*/+ −
#include "sqliteInt.h"+ −
+ −
/*+ −
** Conversion types fall into various categories as defined by the+ −
** following enumeration.+ −
*/+ −
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */+ −
#define etFLOAT 2 /* Floating point. %f */+ −
#define etEXP 3 /* Exponentional notation. %e and %E */+ −
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */+ −
#define etSIZE 5 /* Return number of characters processed so far. %n */+ −
#define etSTRING 6 /* Strings. %s */+ −
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */+ −
#define etPERCENT 8 /* Percent symbol. %% */+ −
#define etCHARX 9 /* Characters. %c */+ −
/* The rest are extensions, not normally found in printf() */+ −
#define etCHARLIT 10 /* Literal characters. %' */+ −
#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */+ −
#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',+ −
NULL pointers replaced by SQL NULL. %Q */+ −
#define etTOKEN 13 /* a pointer to a Token structure */+ −
#define etSRCLIST 14 /* a pointer to a SrcList */+ −
#define etPOINTER 15 /* The %p conversion */+ −
#define etSQLESCAPE3 16 /* %w -> Strings with '\"' doubled */+ −
#define etORDINAL 17 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */+ −
+ −
+ −
/*+ −
** An "etByte" is an 8-bit unsigned value.+ −
*/+ −
typedef unsigned char etByte;+ −
+ −
/*+ −
** Each builtin conversion character (ex: the 'd' in "%d") is described+ −
** by an instance of the following structure+ −
*/+ −
typedef struct et_info { /* Information about each format field */+ −
char fmttype; /* The format field code letter */+ −
etByte base; /* The base for radix conversion */+ −
etByte flags; /* One or more of FLAG_ constants below */+ −
etByte type; /* Conversion paradigm */+ −
etByte charset; /* Offset into aDigits[] of the digits string */+ −
etByte prefix; /* Offset into aPrefix[] of the prefix string */+ −
} et_info;+ −
+ −
/*+ −
** Allowed values for et_info.flags+ −
*/+ −
#define FLAG_SIGNED 1 /* True if the value to convert is signed */+ −
#define FLAG_INTERN 2 /* True if for internal use only */+ −
#define FLAG_STRING 4 /* Allow infinity precision */+ −
+ −
+ −
/*+ −
** The following table is searched linearly, so it is good to put the+ −
** most frequently used conversion types first.+ −
*/+ −
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";+ −
static const char aPrefix[] = "-x0\000X0";+ −
static const et_info fmtinfo[] = {+ −
{ 'd', 10, 1, etRADIX, 0, 0 },+ −
{ 's', 0, 4, etSTRING, 0, 0 },+ −
{ 'g', 0, 1, etGENERIC, 30, 0 },+ −
{ 'z', 0, 4, etDYNSTRING, 0, 0 },+ −
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },+ −
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },+ −
{ 'w', 0, 4, etSQLESCAPE3, 0, 0 },+ −
{ 'c', 0, 0, etCHARX, 0, 0 },+ −
{ 'o', 8, 0, etRADIX, 0, 2 },+ −
{ 'u', 10, 0, etRADIX, 0, 0 },+ −
{ 'x', 16, 0, etRADIX, 16, 1 },+ −
{ 'X', 16, 0, etRADIX, 0, 4 },+ −
#ifndef SQLITE_OMIT_FLOATING_POINT+ −
{ 'f', 0, 1, etFLOAT, 0, 0 },+ −
{ 'e', 0, 1, etEXP, 30, 0 },+ −
{ 'E', 0, 1, etEXP, 14, 0 },+ −
{ 'G', 0, 1, etGENERIC, 14, 0 },+ −
#endif+ −
{ 'i', 10, 1, etRADIX, 0, 0 },+ −
{ 'n', 0, 0, etSIZE, 0, 0 },+ −
{ '%', 0, 0, etPERCENT, 0, 0 },+ −
{ 'p', 16, 0, etPOINTER, 0, 1 },+ −
{ 'T', 0, 2, etTOKEN, 0, 0 },+ −
{ 'S', 0, 2, etSRCLIST, 0, 0 },+ −
{ 'r', 10, 3, etORDINAL, 0, 0 },+ −
};+ −
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))+ −
+ −
/*+ −
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point+ −
** conversions will work.+ −
*/+ −
#ifndef SQLITE_OMIT_FLOATING_POINT+ −
/*+ −
** "*val" is a double such that 0.1 <= *val < 10.0+ −
** Return the ascii code for the leading digit of *val, then+ −
** multiply "*val" by 10.0 to renormalize.+ −
**+ −
** Example:+ −
** input: *val = 3.14159+ −
** output: *val = 1.4159 function return = '3'+ −
**+ −
** The counter *cnt is incremented each time. After counter exceeds+ −
** 16 (the number of significant digits in a 64-bit float) '0' is+ −
** always returned.+ −
*/+ −
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){+ −
int digit;+ −
LONGDOUBLE_TYPE d;+ −
if( (*cnt)++ >= 16 ) return '0';+ −
digit = (int)*val;+ −
d = digit;+ −
digit += '0';+ −
*val = (*val - d)*10.0;+ −
return digit;+ −
}+ −
#endif /* SQLITE_OMIT_FLOATING_POINT */+ −
+ −
/*+ −
** Append N space characters to the given string buffer.+ −
*/+ −
static void appendSpace(StrAccum *pAccum, int N){+ −
static const char zSpaces[] = " ";+ −
while( N>=sizeof(zSpaces)-1 ){+ −
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);+ −
N -= sizeof(zSpaces)-1;+ −
}+ −
if( N>0 ){+ −
sqlite3StrAccumAppend(pAccum, zSpaces, N);+ −
}+ −
}+ −
+ −
/*+ −
** On machines with a small stack size, you can redefine the+ −
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for+ −
** smaller values some %f conversions may go into an infinite loop.+ −
*/+ −
#ifndef SQLITE_PRINT_BUF_SIZE+ −
# define SQLITE_PRINT_BUF_SIZE 350+ −
#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.+ −
*/+ −
static void vxprintf(+ −
StrAccum *pAccum, /* Accumulate results here */+ −
int useExtended, /* Allow extended %-conversions */+ −
const char *fmt, /* Format string */+ −
va_list ap /* arguments */+ −
){+ −
int c; /* Next character in the format string */+ −
char *bufpt; /* Pointer to the conversion buffer */+ −
int precision; /* Precision of the current field */+ −
int length; /* Length of the field */+ −
int idx; /* A general purpose loop counter */+ −
int width; /* Width of the current field */+ −
etByte flag_leftjustify; /* True if "-" flag is present */+ −
etByte flag_plussign; /* True if "+" flag is present */+ −
etByte flag_blanksign; /* True if " " flag is present */+ −
etByte flag_alternateform; /* True if "#" flag is present */+ −
etByte flag_altform2; /* True if "!" flag is present */+ −
etByte flag_zeropad; /* True if field width constant starts with zero */+ −
etByte flag_long; /* True if "l" flag is present */+ −
etByte flag_longlong; /* True if the "ll" flag is present */+ −
etByte done; /* Loop termination flag */+ −
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 errorflag = 0; /* True if an error is encountered */+ −
etByte xtype; /* Conversion paradigm */+ −
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */+ −
#ifndef SQLITE_OMIT_FLOATING_POINT+ −
int exp, e2; /* exponent of real numbers */+ −
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+ −
+ −
length = 0;+ −
bufpt = 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( (c=(*++fmt))==0 ){+ −
errorflag = 1;+ −
sqlite3StrAccumAppend(pAccum, "%", 1);+ −
break;+ −
}+ −
/* Find out what flags are present */+ −
flag_leftjustify = flag_plussign = flag_blanksign = + −
flag_alternateform = flag_altform2 = flag_zeropad = 0;+ −
done = 0;+ −
do{+ −
switch( c ){+ −
case '-': flag_leftjustify = 1; break;+ −
case '+': flag_plussign = 1; break;+ −
case ' ': flag_blanksign = 1; break;+ −
case '#': flag_alternateform = 1; break;+ −
case '!': flag_altform2 = 1; break;+ −
case '0': flag_zeropad = 1; break;+ −
default: done = 1; break;+ −
}+ −
}while( !done && (c=(*++fmt))!=0 );+ −
/* Get the field width */+ −
width = 0;+ −
if( c=='*' ){+ −
width = va_arg(ap,int);+ −
if( width<0 ){+ −
flag_leftjustify = 1;+ −
width = -width;+ −
}+ −
c = *++fmt;+ −
}else{+ −
while( c>='0' && c<='9' ){+ −
width = width*10 + c - '0';+ −
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( precision<0 ) precision = -precision;+ −
c = *++fmt;+ −
}else{+ −
while( c>='0' && c<='9' ){+ −
precision = precision*10 + c - '0';+ −
c = *++fmt;+ −
}+ −
}+ −
}else{+ −
precision = -1;+ −
}+ −
/* Get the conversion type modifier */+ −
if( c=='l' ){+ −
flag_long = 1;+ −
c = *++fmt;+ −
if( c=='l' ){+ −
flag_longlong = 1;+ −
c = *++fmt;+ −
}else{+ −
flag_longlong = 0;+ −
}+ −
}else{+ −
flag_long = flag_longlong = 0;+ −
}+ −
/* Fetch the info entry for the field */+ −
infop = 0;+ −
for(idx=0; idx<etNINFO; idx++){+ −
if( c==fmtinfo[idx].fmttype ){+ −
infop = &fmtinfo[idx];+ −
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){+ −
xtype = infop->type;+ −
}else{+ −
return;+ −
}+ −
break;+ −
}+ −
}+ −
zExtra = 0;+ −
if( infop==0 ){+ −
return;+ −
}+ −
+ −
+ −
/* 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:+ −
**+ −
** flag_alternateform TRUE if a '#' is present.+ −
** flag_altform2 TRUE if a '!' is present.+ −
** flag_plussign TRUE if a '+' is present.+ −
** flag_leftjustify TRUE if a '-' is present or if the+ −
** field width was negative.+ −
** flag_zeropad TRUE if the width began with 0.+ −
** flag_long TRUE if the letter 'l' (ell) prefixed+ −
** the conversion character.+ −
** flag_longlong TRUE if the letter 'll' (ell ell) prefixed+ −
** the conversion character.+ −
** flag_blanksign TRUE if a ' ' is present.+ −
** width The specified field width. This is+ −
** always non-negative. Zero is the default.+ −
** precision The specified precision. The default+ −
** is -1.+ −
** xtype The class of the conversion.+ −
** infop Pointer to the appropriate info struct.+ −
*/+ −
switch( xtype ){+ −
case etPOINTER:+ −
flag_longlong = sizeof(char*)==sizeof(i64);+ −
flag_long = sizeof(char*)==sizeof(long int);+ −
/* Fall through into the next case */+ −
case etORDINAL:+ −
case etRADIX:+ −
if( infop->flags & FLAG_SIGNED ){+ −
i64 v;+ −
if( flag_longlong ) v = va_arg(ap,i64);+ −
else if( flag_long ) v = va_arg(ap,long int);+ −
else v = va_arg(ap,int);+ −
if( v<0 ){+ −
longvalue = -v;+ −
prefix = '-';+ −
}else{+ −
longvalue = v;+ −
if( flag_plussign ) prefix = '+';+ −
else if( flag_blanksign ) prefix = ' ';+ −
else prefix = 0;+ −
}+ −
}else{+ −
if( flag_longlong ) longvalue = va_arg(ap,u64);+ −
else if( flag_long ) longvalue = va_arg(ap,unsigned long int);+ −
else longvalue = va_arg(ap,unsigned int);+ −
prefix = 0;+ −
}+ −
if( longvalue==0 ) flag_alternateform = 0;+ −
if( flag_zeropad && precision<width-(prefix!=0) ){+ −
precision = width-(prefix!=0);+ −
}+ −
bufpt = &buf[etBUFSIZE-1];+ −
if( xtype==etORDINAL ){+ −
static const char zOrd[] = "thstndrd";+ −
int x = 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;+ −
}+ −
{+ −
register const char *cset; /* Use registers for speed */+ −
register int base;+ −
cset = &aDigits[infop->charset];+ −
base = infop->base;+ −
do{ /* Convert to ascii */+ −
*(--bufpt) = cset[longvalue%base];+ −
longvalue = longvalue/base;+ −
}while( longvalue>0 );+ −
}+ −
length = &buf[etBUFSIZE-1]-bufpt;+ −
for(idx=precision-length; idx>0; idx--){+ −
*(--bufpt) = '0'; /* Zero pad */+ −
}+ −
if( prefix ) *(--bufpt) = prefix; /* Add sign */+ −
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */+ −
const char *pre;+ −
char x;+ −
pre = &aPrefix[infop->prefix];+ −
if( *bufpt!=pre[0] ){+ −
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;+ −
}+ −
}+ −
length = &buf[etBUFSIZE-1]-bufpt;+ −
break;+ −
case etFLOAT:+ −
case etEXP:+ −
case etGENERIC:+ −
realvalue = va_arg(ap,double);+ −
#ifndef SQLITE_OMIT_FLOATING_POINT+ −
if( precision<0 ) precision = 6; /* Set default precision */+ −
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;+ −
if( realvalue<0.0 ){+ −
realvalue = -realvalue;+ −
prefix = '-';+ −
}else{+ −
if( flag_plussign ) prefix = '+';+ −
else if( flag_blanksign ) prefix = ' ';+ −
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;+ −
if( sqlite3_isnan(realvalue) ){+ −
bufpt = "NaN";+ −
length = 3;+ −
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++; }+ −
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }+ −
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }+ −
if( exp>350 || exp<-350 ){+ −
if( prefix=='-' ){+ −
bufpt = "-Inf";+ −
}else if( prefix=='+' ){+ −
bufpt = "+Inf";+ −
}else{+ −
bufpt = "Inf";+ −
}+ −
length = strlen(bufpt);+ −
break;+ −
}+ −
}+ −
bufpt = buf;+ −
/*+ −
** 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++; }+ −
}+ −
if( xtype==etGENERIC ){+ −
flag_rtz = !flag_alternateform;+ −
if( exp<-4 || exp>precision ){+ −
xtype = etEXP;+ −
}else{+ −
precision = precision - exp;+ −
xtype = etFLOAT;+ −
}+ −
}else{+ −
flag_rtz = 0;+ −
}+ −
if( xtype==etEXP ){+ −
e2 = 0;+ −
}else{+ −
e2 = exp;+ −
}+ −
nsd = 0;+ −
flag_dp = (precision>0) | flag_alternateform | flag_altform2;+ −
/* The sign in front of the number */+ −
if( prefix ){+ −
*(bufpt++) = prefix;+ −
}+ −
/* Digits prior to the decimal point */+ −
if( e2<0 ){+ −
*(bufpt++) = '0';+ −
}else{+ −
for(; e2>=0; e2--){+ −
*(bufpt++) = et_getdigit(&realvalue,&nsd);+ −
}+ −
}+ −
/* The decimal point */+ −
if( flag_dp ){+ −
*(bufpt++) = '.';+ −
}+ −
/* "0" digits after the decimal point but before the first+ −
** significant digit of the number */+ −
for(e2++; e2<0 && precision>0; precision--, e2++){+ −
*(bufpt++) = '0';+ −
}+ −
/* Significant digits after the decimal point */+ −
while( (precision--)>0 ){+ −
*(bufpt++) = et_getdigit(&realvalue,&nsd);+ −
}+ −
/* Remove trailing zeros and the "." if no digits follow the "." */+ −
if( flag_rtz && flag_dp ){+ −
while( bufpt[-1]=='0' ) *(--bufpt) = 0;+ −
assert( bufpt>buf );+ −
if( bufpt[-1]=='.' ){+ −
if( flag_altform2 ){+ −
*(bufpt++) = '0';+ −
}else{+ −
*(--bufpt) = 0;+ −
}+ −
}+ −
}+ −
/* Add the "eNNN" suffix */+ −
if( flag_exp || (xtype==etEXP && exp) ){+ −
*(bufpt++) = aDigits[infop->charset];+ −
if( exp<0 ){+ −
*(bufpt++) = '-'; exp = -exp;+ −
}else{+ −
*(bufpt++) = '+';+ −
}+ −
if( exp>=100 ){+ −
*(bufpt++) = (exp/100)+'0'; /* 100's digit */+ −
exp %= 100;+ −
}+ −
*(bufpt++) = exp/10+'0'; /* 10's digit */+ −
*(bufpt++) = exp%10+'0'; /* 1's digit */+ −
}+ −
*bufpt = 0;+ −
+ −
/* 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 = bufpt-buf;+ −
bufpt = buf;+ −
+ −
/* Special case: Add leading zeros if the flag_zeropad flag is+ −
** set and we are not left justified */+ −
if( flag_zeropad && !flag_leftjustify && length < width){+ −
int i;+ −
int nPad = width - length;+ −
for(i=width; i>=nPad; i--){+ −
bufpt[i] = bufpt[i-nPad];+ −
}+ −
i = prefix!=0;+ −
while( nPad-- ) bufpt[i++] = '0';+ −
length = width;+ −
}+ −
#endif+ −
break;+ −
case etSIZE:+ −
*(va_arg(ap,int*)) = pAccum->nChar;+ −
length = width = 0;+ −
break;+ −
case etPERCENT:+ −
buf[0] = '%';+ −
bufpt = buf;+ −
length = 1;+ −
break;+ −
case etCHARLIT:+ −
case etCHARX:+ −
c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);+ −
if( precision>=0 ){+ −
for(idx=1; idx<precision; idx++) buf[idx] = c;+ −
length = precision;+ −
}else{+ −
length =1;+ −
}+ −
bufpt = buf;+ −
break;+ −
case etSTRING:+ −
case etDYNSTRING:+ −
bufpt = va_arg(ap,char*);+ −
if( bufpt==0 ){+ −
bufpt = "";+ −
}else if( xtype==etDYNSTRING ){+ −
zExtra = bufpt;+ −
}+ −
length = strlen(bufpt);+ −
if( precision>=0 && precision<length ) length = precision;+ −
break;+ −
case etSQLESCAPE:+ −
case etSQLESCAPE2:+ −
case etSQLESCAPE3: {+ −
int i, j, n, ch, isnull;+ −
int needQuote;+ −
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */+ −
char *escarg = va_arg(ap,char*);+ −
isnull = escarg==0;+ −
if( isnull ) escarg = (char*)(xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");+ −
for(i=n=0; (ch=escarg[i])!=0; i++){+ −
if( ch==q ) n++;+ −
}+ −
needQuote = !isnull && xtype==etSQLESCAPE2;+ −
n += i + 1 + needQuote*2;+ −
if( n>etBUFSIZE ){+ −
bufpt = zExtra = (char*)sqlite3_malloc( n );+ −
if( bufpt==0 ) return;+ −
}else{+ −
bufpt = buf;+ −
}+ −
j = 0;+ −
if( needQuote ) bufpt[j++] = q;+ −
for(i=0; (ch=escarg[i])!=0; i++){+ −
bufpt[j++] = ch;+ −
if( ch==q ) bufpt[j++] = ch;+ −
}+ −
if( needQuote ) bufpt[j++] = q;+ −
bufpt[j] = 0;+ −
length = j;+ −
/* The precision is ignored on %q and %Q */+ −
/* if( precision>=0 && precision<length ) length = precision; */+ −
break;+ −
}+ −
case etTOKEN: {+ −
Token *pToken = va_arg(ap, Token*);+ −
if( pToken && pToken->z ){+ −
sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);+ −
}+ −
length = width = 0;+ −
break;+ −
}+ −
case etSRCLIST: {+ −
SrcList *pSrc = va_arg(ap, SrcList*);+ −
int k = va_arg(ap, int);+ −
SrcList::SrcList_item *pItem = &pSrc->a[k];+ −
assert( k>=0 && k<pSrc->nSrc );+ −
if( pItem->zDatabase && pItem->zDatabase[0] ){+ −
sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);+ −
sqlite3StrAccumAppend(pAccum, ".", 1);+ −
}+ −
sqlite3StrAccumAppend(pAccum, pItem->zName, -1);+ −
length = width = 0;+ −
break;+ −
}+ −
}/* End switch over the format type */+ −
/*+ −
** The text of the conversion is pointed to by "bufpt" and is+ −
** "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);+ −
}+ −
}+ −
if( zExtra ){+ −
sqlite3_free(zExtra);+ −
}+ −
}/* End for loop over the format string */+ −
} /* End of function */+ −
+ −
/*+ −
** Append N bytes of text from z to the StrAccum object.+ −
*/+ −
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){+ −
if( p->tooBig | p->mallocFailed ){+ −
return;+ −
}+ −
if( N<0 ){+ −
N = strlen(z);+ −
}+ −
if( N==0 ){+ −
return;+ −
}+ −
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{+ −
p->nAlloc += p->nAlloc + N + 1;+ −
if( p->nAlloc > SQLITE_MAX_LENGTH ){+ −
p->nAlloc = SQLITE_MAX_LENGTH;+ −
if( p->nChar+N >= p->nAlloc ){+ −
sqlite3StrAccumReset(p);+ −
p->tooBig = 1;+ −
return;+ −
}+ −
}+ −
zNew = (char*)sqlite3_malloc( p->nAlloc );+ −
if( zNew ){+ −
memcpy(zNew, p->zText, p->nChar);+ −
sqlite3StrAccumReset(p);+ −
p->zText = zNew;+ −
}else{+ −
p->mallocFailed = 1;+ −
sqlite3StrAccumReset(p);+ −
return;+ −
}+ −
}+ −
}+ −
memcpy(&p->zText[p->nChar], z, N);+ −
p->nChar += N;+ −
}+ −
+ −
/*+ −
** 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.+ −
*/+ −
char *sqlite3StrAccumFinish(StrAccum *p){+ −
if( p->zText ){+ −
p->zText[p->nChar] = 0;+ −
if( p->useMalloc && p->zText==p->zBase ){+ −
p->zText = (char*)sqlite3_malloc( p->nChar+1 );+ −
if( p->zText ){+ −
memcpy(p->zText, p->zBase, p->nChar+1);+ −
}else{+ −
p->mallocFailed = 1;+ −
}+ −
}+ −
}+ −
return p->zText;+ −
}+ −
+ −
/*+ −
** Reset an StrAccum string. Reclaim all malloced memory.+ −
*/+ −
void sqlite3StrAccumReset(StrAccum *p){+ −
if( p->zText!=p->zBase ){+ −
sqlite3_free(p->zText);+ −
p->zText = 0;+ −
}+ −
}+ −
+ −
/*+ −
** Initialize a string accumulator+ −
*/+ −
static void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n){+ −
p->zText = p->zBase = zBase;+ −
p->nChar = 0;+ −
p->nAlloc = n;+ −
p->useMalloc = 1;+ −
p->tooBig = 0;+ −
p->mallocFailed = 0;+ −
}+ −
+ −
/*+ −
** Print into memory obtained from sqliteMalloc(). Use the internal+ −
** %-conversion extensions.+ −
*/+ −
char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){+ −
char *z;+ −
char zBase[SQLITE_PRINT_BUF_SIZE];+ −
StrAccum acc;+ −
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase));+ −
vxprintf(&acc, 1, zFormat, ap);+ −
z = sqlite3StrAccumFinish(&acc);+ −
if( acc.mallocFailed && db ){+ −
db->mallocFailed = 1;+ −
}+ −
return z;+ −
}+ −
+ −
/*+ −
** Print into memory obtained from sqliteMalloc(). Use the internal+ −
** %-conversion extensions.+ −
*/+ −
char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){+ −
va_list ap;+ −
char *z;+ −
va_start(ap, zFormat);+ −
z = sqlite3VMPrintf(db, zFormat, ap);+ −
va_end(ap);+ −
return z;+ −
}+ −
+ −
/*+ −
** Print into memory obtained from sqlite3_malloc(). Omit the internal+ −
** %-conversion extensions.+ −
*/+ −
EXPORT_C char *sqlite3_vmprintf(const char *zFormat, va_list ap){+ −
char *z;+ −
char zBase[SQLITE_PRINT_BUF_SIZE];+ −
StrAccum acc;+ −
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase));+ −
vxprintf(&acc, 0, zFormat, ap);+ −
z = sqlite3StrAccumFinish(&acc);+ −
return z;+ −
}+ −
+ −
/*+ −
** Print into memory obtained from sqlite3_malloc()(). Omit the internal+ −
** %-conversion extensions.+ −
*/+ −
EXPORT_C char *sqlite3_mprintf(const char *zFormat, ...){+ −
va_list ap;+ −
char *z;+ −
va_start(ap, zFormat);+ −
z = sqlite3_vmprintf(zFormat, ap);+ −
va_end(ap);+ −
return z;+ −
}+ −
+ −
/*+ −
** sqlite3_snprintf() works like snprintf() except that it ignores the+ −
** current locale settings. This is important for SQLite because we+ −
** are not able to use a "," as the decimal point in place of "." as+ −
** specified by some locales.+ −
*/+ −
EXPORT_C char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){+ −
char *z;+ −
va_list ap;+ −
StrAccum acc;+ −
+ −
if( n<=0 ){+ −
return zBuf;+ −
}+ −
sqlite3StrAccumInit(&acc, zBuf, n);+ −
acc.useMalloc = 0;+ −
va_start(ap,zFormat);+ −
vxprintf(&acc, 0, zFormat, ap);+ −
va_end(ap);+ −
z = sqlite3StrAccumFinish(&acc);+ −
return z;+ −
}+ −
+ −
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) || defined(SQLITE_MEMDEBUG)+ −
/*+ −
** A version of printf() that understands %lld. Used for debugging.+ −
** The printf() built into some versions of windows does not understand %lld+ −
** and segfaults if you give it a long long int.+ −
*/+ −
void sqlite3DebugPrintf(const char *zFormat, ...){+ −
va_list ap;+ −
StrAccum acc;+ −
char zBuf[500];+ −
sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf));+ −
acc.useMalloc = 0;+ −
va_start(ap,zFormat);+ −
vxprintf(&acc, 0, zFormat, ap);+ −
va_end(ap);+ −
sqlite3StrAccumFinish(&acc);+ −
fprintf(stdout,"%s", zBuf);+ −
fflush(stdout);+ −
}+ −
#endif+ −