aboutsummaryrefslogtreecommitdiff
path: root/src/printf.c
diff options
context:
space:
mode:
authordan <dan@noemail.net>2015-01-01 18:03:49 +0000
committerdan <dan@noemail.net>2015-01-01 18:03:49 +0000
commit37db72f1f7ca41c61b1c084bdb75f3111ceba6f8 (patch)
tree5a01dcb28b6513353a64e93b11d6243845e69bc7 /src/printf.c
parent6024772ba292a9abc6810dd0b12767d02b47ccf1 (diff)
parenta0de826c9ff84bd19de76ebbc0d4bdafa9686d3a (diff)
downloadsqlite-37db72f1f7ca41c61b1c084bdb75f3111ceba6f8.tar.gz
sqlite-37db72f1f7ca41c61b1c084bdb75f3111ceba6f8.zip
Merge latest trunk changes with this branch.
FossilOrigin-Name: 4b3651677e7132c4c45605bc1f216fc08ef31198
Diffstat (limited to 'src/printf.c')
-rw-r--r--src/printf.c154
1 files changed, 132 insertions, 22 deletions
diff --git a/src/printf.c b/src/printf.c
index 37910804d..ac7b05163 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -15,6 +15,17 @@
#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.
*/
@@ -201,7 +212,7 @@ void sqlite3VXPrintf(
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
- char *zExtra; /* Malloced memory used by some conversion */
+ 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 */
@@ -212,6 +223,13 @@ void sqlite3VXPrintf(
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ap==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ sqlite3StrAccumReset(pAccum);
+ return;
+ }
+#endif
bufpt = 0;
if( bFlags ){
if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
@@ -224,9 +242,13 @@ void sqlite3VXPrintf(
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
bufpt = (char *)fmt;
- while( (c=(*++fmt))!='%' && c!=0 ){};
+#if HAVE_STRCHRNUL
+ fmt = strchrnul(fmt, '%');
+#else
+ do{ fmt++; }while( *fmt && *fmt != '%' );
+#endif
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
- if( c==0 ) break;
+ if( *fmt==0 ) break;
}
if( (c=(*++fmt))==0 ){
sqlite3StrAccumAppend(pAccum, "%", 1);
@@ -314,7 +336,6 @@ void sqlite3VXPrintf(
break;
}
}
- zExtra = 0;
/*
** At this point, variables are initialized as follows:
@@ -605,13 +626,16 @@ void sqlite3VXPrintf(
}else{
c = va_arg(ap,int);
}
- buf[0] = (char)c;
- if( precision>=0 ){
- for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
- length = precision;
- }else{
- length =1;
+ 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:
@@ -712,11 +736,14 @@ void sqlite3VXPrintf(
** the output.
*/
width -= length;
- if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
+ if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
sqlite3StrAccumAppend(pAccum, bufpt, length);
- if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
+ if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
- if( zExtra ) sqlite3_free(zExtra);
+ if( zExtra ){
+ sqlite3_free(zExtra);
+ zExtra = 0;
+ }
}/* End for loop over the format string */
} /* End of function */
@@ -743,6 +770,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
+ if( szNew+p->nChar<=p->mxAlloc ){
+ /* Force exponential buffer size growth as long as it does not overflow,
+ ** to avoid having to call this routine too often */
+ szNew += p->nChar;
+ }
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
@@ -759,6 +791,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
assert( p->zText!=0 || p->nChar==0 );
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
+ p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
@@ -769,11 +802,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}
/*
-** Append N space characters to the given string buffer.
+** Append N copies of character c to the given string buffer.
*/
-void sqlite3AppendSpace(StrAccum *p, int N){
+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++] = ' ';
+ while( (N--)>0 ) p->zText[p->nChar++] = c;
}
/*
@@ -784,7 +817,7 @@ void sqlite3AppendSpace(StrAccum *p, int N){
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
*/
-static void enlargeAndAppend(StrAccum *p, const char *z, int N){
+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);
@@ -803,11 +836,11 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
- return;
+ }else{
+ assert( p->zText );
+ p->nChar += N;
+ memcpy(&p->zText[p->nChar-N], z, N);
}
- assert( p->zText );
- memcpy(&p->zText[p->nChar], z, N);
- p->nChar += N;
}
/*
@@ -904,7 +937,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);
@@ -928,6 +961,13 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zFormat==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -970,6 +1010,13 @@ char *sqlite3_mprintf(const char *zFormat, ...){
char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf && n>0 ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
sqlite3StrAccumInit(&acc, zBuf, n, 0);
acc.useMalloc = 0;
sqlite3VXPrintf(&acc, 0, zFormat, ap);
@@ -1037,6 +1084,69 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
}
#endif
+#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().
*/