diff options
Diffstat (limited to 'lang/sql/sqlite/src/printf.c')
-rw-r--r-- | lang/sql/sqlite/src/printf.c | 337 |
1 files changed, 174 insertions, 163 deletions
diff --git a/lang/sql/sqlite/src/printf.c b/lang/sql/sqlite/src/printf.c index 2a3dd81d..8cfa542b 100644 --- a/lang/sql/sqlite/src/printf.c +++ b/lang/sql/sqlite/src/printf.c @@ -7,48 +7,10 @@ ** ************************************************************************** ** -** 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" @@ -162,7 +124,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'; @@ -174,7 +137,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ /* ** Append N space characters to the given string buffer. */ -static void appendSpace(StrAccum *pAccum, int N){ +void sqlite3AppendSpace(StrAccum *pAccum, int N){ static const char zSpaces[] = " "; while( N>=(int)sizeof(zSpaces)-1 ){ sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1); @@ -186,50 +149,47 @@ static void appendSpace(StrAccum *pAccum, int N){ } /* +** Set the StrAccum object to an error mode. +*/ +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,24 +206,35 @@ 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; /* 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; @@ -295,7 +266,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 +282,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 +322,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; @@ -356,12 +332,6 @@ void sqlite3VXPrintf( } 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 +362,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 +385,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,16 +400,26 @@ 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 */ @@ -447,7 +431,7 @@ void sqlite3VXPrintf( 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 +442,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 +465,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 +475,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 +500,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 +513,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 +559,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 +569,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 +588,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 +606,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,7 +617,12 @@ void sqlite3VXPrintf( length = 1; break; case etCHARX: - c = va_arg(ap,int); + if( bArgList ){ + bufpt = getTextArg(pArgList); + c = bufpt ? bufpt[0] : 0; + }else{ + c = va_arg(ap,int); + } buf[0] = (char)c; if( precision>=0 ){ for(idx=1; idx<precision; idx++) buf[idx] = (char)c; @@ -636,10 +634,14 @@ void sqlite3VXPrintf( 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 +657,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 +675,7 @@ void sqlite3VXPrintf( if( n>etBUFSIZE ){ bufpt = zExtra = sqlite3Malloc( n ); if( bufpt==0 ){ - pAccum->mallocFailed = 1; + setStrAccumError(pAccum, STRACCUM_NOMEM); return; } }else{ @@ -690,7 +698,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 +709,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; } @@ -723,7 +733,7 @@ void sqlite3VXPrintf( register int nspace; nspace = width-length; if( nspace>0 ){ - appendSpace(pAccum, nspace); + sqlite3AppendSpace(pAccum, nspace); } } if( length>0 ){ @@ -733,12 +743,10 @@ void sqlite3VXPrintf( register int nspace; nspace = width-length; if( nspace>0 ){ - appendSpace(pAccum, nspace); + sqlite3AppendSpace(pAccum, nspace); } } - if( zExtra ){ - sqlite3_free(zExtra); - } + if( zExtra ) sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ @@ -746,23 +754,20 @@ void sqlite3VXPrintf( ** Append N bytes of text from z to the StrAccum object. */ 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; - } - if( N<0 ){ - N = sqlite3Strlen30(z); - } - if( N==0 || NEVER(z==0) ){ - return; - } + 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->accError ){ + testcase(p->accError==STRACCUM_TOOBIG); + testcase(p->accError==STRACCUM_NOMEM); + return; + } if( !p->useMalloc ){ - p->tooBig = 1; N = p->nAlloc - p->nChar - 1; + setStrAccumError(p, STRACCUM_TOOBIG); if( N<=0 ){ return; } @@ -772,7 +777,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ szNew += N + 1; if( szNew > p->mxAlloc ){ sqlite3StrAccumReset(p); - p->tooBig = 1; + setStrAccumError(p, STRACCUM_TOOBIG); return; }else{ p->nAlloc = (int)szNew; @@ -783,20 +788,29 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ zNew = sqlite3_realloc(zOld, p->nAlloc); } if( zNew ){ - if( zOld==0 ) memcpy(zNew, p->zText, p->nChar); + if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; }else{ - p->mallocFailed = 1; sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_NOMEM); return; } } } + assert( p->zText ); 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 +827,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 +858,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 +873,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; @@ -1016,14 +1029,12 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ } #endif -#ifndef SQLITE_OMIT_TRACE /* ** 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 |