File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2006 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** An implementation of printf() with extra conversion fields.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "printf.h"
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Conversion types fall into various categories as defined by the
dbda8d6ce9 2007-07-21       drh: ** following enumeration.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
dbda8d6ce9 2007-07-21       drh: #define etFLOAT       2 /* Floating point.  %f */
dbda8d6ce9 2007-07-21       drh: #define etEXP         3 /* Exponentional notation. %e and %E */
dbda8d6ce9 2007-07-21       drh: #define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
dbda8d6ce9 2007-07-21       drh: #define etSIZE        5 /* Return number of characters processed so far. %n */
dbda8d6ce9 2007-07-21       drh: #define etSTRING      6 /* Strings. %s */
dbda8d6ce9 2007-07-21       drh: #define etDYNSTRING   7 /* Dynamically allocated strings. %z */
dbda8d6ce9 2007-07-21       drh: #define etPERCENT     8 /* Percent symbol. %% */
dbda8d6ce9 2007-07-21       drh: #define etCHARX       9 /* Characters. %c */
dbda8d6ce9 2007-07-21       drh: #define etERROR      10 /* Used to indicate no such conversion type */
dbda8d6ce9 2007-07-21       drh: /* The rest are extensions, not normally found in printf() */
dbda8d6ce9 2007-07-21       drh: #define etBLOB       11 /* Blob objects.  %b */
dbda8d6ce9 2007-07-21       drh: #define etBLOBSQL    12 /* Blob objects quoted for SQL.  %B */
dbda8d6ce9 2007-07-21       drh: #define etSQLESCAPE  13 /* Strings with '\'' doubled.  %q */
dbda8d6ce9 2007-07-21       drh: #define etSQLESCAPE2 14 /* Strings with '\'' doubled and enclosed in '',
dbda8d6ce9 2007-07-21       drh:                           NULL pointers replaced by SQL NULL.  %Q */
dbda8d6ce9 2007-07-21       drh: #define etPOINTER    15 /* The %p conversion */
dbda8d6ce9 2007-07-21       drh: #define etHTMLIZE    16 /* Make text safe for HTML */
dbda8d6ce9 2007-07-21       drh: #define etHTTPIZE    17 /* Make text safe for HTTP.  "/" encoded as %2f */
dbda8d6ce9 2007-07-21       drh: #define etURLIZE     18 /* Make text safe for HTTP.  "/" not encoded */
dbda8d6ce9 2007-07-21       drh: #define etFOSSILIZE  19 /* The fossil header encoding format. */
c7278fd013 2007-09-22       jnc: #define etPATH       20 /* Path type */
2859293737 2007-11-22       drh: #define etWIKISTR    21 /* Wiki text rendered from a char* */
2859293737 2007-11-22       drh: #define etWIKIBLOB   22 /* Wiki text rendered from a Blob* */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** An "etByte" is an 8-bit unsigned value.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef unsigned char etByte;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Each builtin conversion character (ex: the 'd' in "%d") is described
dbda8d6ce9 2007-07-21       drh: ** by an instance of the following structure
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct et_info {   /* Information about each format field */
dbda8d6ce9 2007-07-21       drh:   char fmttype;            /* The format field code letter */
dbda8d6ce9 2007-07-21       drh:   etByte base;             /* The base for radix conversion */
dbda8d6ce9 2007-07-21       drh:   etByte flags;            /* One or more of FLAG_ constants below */
dbda8d6ce9 2007-07-21       drh:   etByte type;             /* Conversion paradigm */
dbda8d6ce9 2007-07-21       drh:   etByte charset;          /* Offset into aDigits[] of the digits string */
dbda8d6ce9 2007-07-21       drh:   etByte prefix;           /* Offset into aPrefix[] of the prefix string */
dbda8d6ce9 2007-07-21       drh: } et_info;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Allowed values for et_info.flags
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define FLAG_SIGNED  1     /* True if the value to convert is signed */
dbda8d6ce9 2007-07-21       drh: #define FLAG_INTERN  2     /* True if for internal use only */
dbda8d6ce9 2007-07-21       drh: #define FLAG_STRING  4     /* Allow infinity precision */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following table is searched linearly, so it is good to put the
dbda8d6ce9 2007-07-21       drh: ** most frequently used conversion types first.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
dbda8d6ce9 2007-07-21       drh: static const char aPrefix[] = "-x0\000X0";
dbda8d6ce9 2007-07-21       drh: static const et_info fmtinfo[] = {
dbda8d6ce9 2007-07-21       drh:   {  'd', 10, 1, etRADIX,      0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  's',  0, 4, etSTRING,     0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'g',  0, 1, etGENERIC,    30, 0 },
dbda8d6ce9 2007-07-21       drh:   {  'z',  0, 6, etDYNSTRING,  0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'q',  0, 4, etSQLESCAPE,  0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'Q',  0, 4, etSQLESCAPE2, 0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'b',  0, 2, etBLOB,       0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'B',  0, 2, etBLOBSQL,    0,  0 },
2859293737 2007-11-22       drh:   {  'w',  0, 2, etWIKISTR,    0,  0 },
2859293737 2007-11-22       drh:   {  'W',  0, 2, etWIKIBLOB,   0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'h',  0, 4, etHTMLIZE,    0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  't',  0, 4, etHTTPIZE,    0,  0 },  /* "/" -> "%2F" */
dbda8d6ce9 2007-07-21       drh:   {  'T',  0, 4, etURLIZE,     0,  0 },  /* "/" unchanged */
dbda8d6ce9 2007-07-21       drh:   {  'F',  0, 4, etFOSSILIZE,  0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'c',  0, 0, etCHARX,      0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'o',  8, 0, etRADIX,      0,  2 },
dbda8d6ce9 2007-07-21       drh:   {  'u', 10, 0, etRADIX,      0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'x', 16, 0, etRADIX,      16, 1 },
dbda8d6ce9 2007-07-21       drh:   {  'X', 16, 0, etRADIX,      0,  4 },
dbda8d6ce9 2007-07-21       drh:   {  'f',  0, 1, etFLOAT,      0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'e',  0, 1, etEXP,        30, 0 },
dbda8d6ce9 2007-07-21       drh:   {  'E',  0, 1, etEXP,        14, 0 },
dbda8d6ce9 2007-07-21       drh:   {  'G',  0, 1, etGENERIC,    14, 0 },
dbda8d6ce9 2007-07-21       drh:   {  'i', 10, 1, etRADIX,      0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'n',  0, 0, etSIZE,       0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  '%',  0, 0, etPERCENT,    0,  0 },
dbda8d6ce9 2007-07-21       drh:   {  'p', 16, 0, etPOINTER,    0,  1 },
c7278fd013 2007-09-22       jnc:   {  '/',  0, 0, etPATH,       0,  0 },
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: #define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** "*val" is a double such that 0.1 <= *val < 10.0
dbda8d6ce9 2007-07-21       drh: ** Return the ascii code for the leading digit of *val, then
dbda8d6ce9 2007-07-21       drh: ** multiply "*val" by 10.0 to renormalize.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Example:
dbda8d6ce9 2007-07-21       drh: **     input:     *val = 3.14159
dbda8d6ce9 2007-07-21       drh: **     output:    *val = 1.4159    function return = '3'
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The counter *cnt is incremented each time.  After counter exceeds
dbda8d6ce9 2007-07-21       drh: ** 16 (the number of significant digits in a 64-bit float) '0' is
dbda8d6ce9 2007-07-21       drh: ** always returned.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int et_getdigit(long double *val, int *cnt){
dbda8d6ce9 2007-07-21       drh:   int digit;
dbda8d6ce9 2007-07-21       drh:   long double d;
dbda8d6ce9 2007-07-21       drh:   if( (*cnt)++ >= 16 ) return '0';
dbda8d6ce9 2007-07-21       drh:   digit = (int)*val;
dbda8d6ce9 2007-07-21       drh:   d = digit;
dbda8d6ce9 2007-07-21       drh:   digit += '0';
dbda8d6ce9 2007-07-21       drh:   *val = (*val - d)*10.0;
dbda8d6ce9 2007-07-21       drh:   return digit;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Size of temporary conversion buffer.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define etBUFSIZE 500
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
8c3ec00311 2008-02-04       drh: ** Find the length of a string as long as that length does not
8c3ec00311 2008-02-04       drh: ** exceed N bytes.  If no zero terminator is seen in the first
8c3ec00311 2008-02-04       drh: ** N bytes then return N.  If N is negative, then this routine
8c3ec00311 2008-02-04       drh: ** is an alias for strlen().
8c3ec00311 2008-02-04       drh: */
9a8fdf7294 2009-12-18       drh: static int StrNLen32(const char *z, int N){
8c3ec00311 2008-02-04       drh:   int n = 0;
8c3ec00311 2008-02-04       drh:   while( (N-- != 0) && *(z++)!=0 ){ n++; }
8c3ec00311 2008-02-04       drh:   return n;
8c3ec00311 2008-02-04       drh: }
8c3ec00311 2008-02-04       drh: 
8c3ec00311 2008-02-04       drh: 
8c3ec00311 2008-02-04       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The root program.  All variations call this core.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** INPUTS:
dbda8d6ce9 2007-07-21       drh: **   func   This is a pointer to a function taking three arguments
dbda8d6ce9 2007-07-21       drh: **            1. A pointer to anything.  Same as the "arg" parameter.
dbda8d6ce9 2007-07-21       drh: **            2. A pointer to the list of characters to be output
dbda8d6ce9 2007-07-21       drh: **               (Note, this list is NOT null terminated.)
dbda8d6ce9 2007-07-21       drh: **            3. An integer number of characters to be output.
dbda8d6ce9 2007-07-21       drh: **               (Note: This number might be zero.)
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   arg    This is the pointer to anything which will be passed as the
dbda8d6ce9 2007-07-21       drh: **          first argument to "func".  Use it for whatever you like.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   fmt    This is the format string, as in the usual print.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   ap     This is a pointer to a list of arguments.  Same as in
dbda8d6ce9 2007-07-21       drh: **          vfprint.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** OUTPUTS:
dbda8d6ce9 2007-07-21       drh: **          The return value is the total number of characters sent to
dbda8d6ce9 2007-07-21       drh: **          the function "func".  Returns -1 on a error.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Note that the order in which automatic variables are declared below
dbda8d6ce9 2007-07-21       drh: ** seems to make a big difference in determining how fast this beast
dbda8d6ce9 2007-07-21       drh: ** will run.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: int vxprintf(
2859293737 2007-11-22       drh:   Blob *pBlob,                       /* Append output to this blob */
dbda8d6ce9 2007-07-21       drh:   const char *fmt,                   /* Format string */
dbda8d6ce9 2007-07-21       drh:   va_list ap                         /* arguments */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int c;                     /* Next character in the format string */
dbda8d6ce9 2007-07-21       drh:   char *bufpt;               /* Pointer to the conversion buffer */
dbda8d6ce9 2007-07-21       drh:   int precision;             /* Precision of the current field */
dbda8d6ce9 2007-07-21       drh:   int length;                /* Length of the field */
dbda8d6ce9 2007-07-21       drh:   int idx;                   /* A general purpose loop counter */
dbda8d6ce9 2007-07-21       drh:   int count;                 /* Total number of characters output */
dbda8d6ce9 2007-07-21       drh:   int width;                 /* Width of the current field */
dbda8d6ce9 2007-07-21       drh:   etByte flag_leftjustify;   /* True if "-" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_plussign;      /* True if "+" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_blanksign;     /* True if " " flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_alternateform; /* True if "#" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_altform2;      /* True if "!" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_zeropad;       /* True if field width constant starts with zero */
dbda8d6ce9 2007-07-21       drh:   etByte flag_long;          /* True if "l" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte flag_longlong;      /* True if the "ll" flag is present */
dbda8d6ce9 2007-07-21       drh:   etByte done;               /* Loop termination flag */
dbda8d6ce9 2007-07-21       drh:   u64 longvalue;             /* Value for integer types */
dbda8d6ce9 2007-07-21       drh:   long double realvalue;     /* Value for real types */
dbda8d6ce9 2007-07-21       drh:   const et_info *infop;      /* Pointer to the appropriate info structure */
dbda8d6ce9 2007-07-21       drh:   char buf[etBUFSIZE];       /* Conversion buffer */
dbda8d6ce9 2007-07-21       drh:   char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
dbda8d6ce9 2007-07-21       drh:   etByte errorflag = 0;      /* True if an error is encountered */
dbda8d6ce9 2007-07-21       drh:   etByte xtype;              /* Conversion paradigm */
dbda8d6ce9 2007-07-21       drh:   char *zExtra;              /* Extra memory used for etTCLESCAPE conversions */
dbda8d6ce9 2007-07-21       drh:   static const char spaces[] =
dbda8d6ce9 2007-07-21       drh:    "                                                                         ";
dbda8d6ce9 2007-07-21       drh: #define etSPACESIZE (sizeof(spaces)-1)
dbda8d6ce9 2007-07-21       drh:   int  exp, e2;              /* exponent of real numbers */
dbda8d6ce9 2007-07-21       drh:   double rounder;            /* Used for rounding floating point values */
dbda8d6ce9 2007-07-21       drh:   etByte flag_dp;            /* True if decimal point should be shown */
dbda8d6ce9 2007-07-21       drh:   etByte flag_rtz;           /* True if trailing zeros should be removed */
dbda8d6ce9 2007-07-21       drh:   etByte flag_exp;           /* True to force display of the exponent */
dbda8d6ce9 2007-07-21       drh:   int nsd;                   /* Number of significant digits returned */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   count = length = 0;
dbda8d6ce9 2007-07-21       drh:   bufpt = 0;
dbda8d6ce9 2007-07-21       drh:   for(; (c=(*fmt))!=0; ++fmt){
dbda8d6ce9 2007-07-21       drh:     if( c!='%' ){
dbda8d6ce9 2007-07-21       drh:       int amt;
dbda8d6ce9 2007-07-21       drh:       bufpt = (char *)fmt;
dbda8d6ce9 2007-07-21       drh:       amt = 1;
dbda8d6ce9 2007-07-21       drh:       while( (c=(*++fmt))!='%' && c!=0 ) amt++;
2859293737 2007-11-22       drh:       blob_append(pBlob,bufpt,amt);
dbda8d6ce9 2007-07-21       drh:       count += amt;
dbda8d6ce9 2007-07-21       drh:       if( c==0 ) break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( (c=(*++fmt))==0 ){
dbda8d6ce9 2007-07-21       drh:       errorflag = 1;
2859293737 2007-11-22       drh:       blob_append(pBlob,"%",1);
dbda8d6ce9 2007-07-21       drh:       count++;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     /* Find out what flags are present */
dbda8d6ce9 2007-07-21       drh:     flag_leftjustify = flag_plussign = flag_blanksign =
dbda8d6ce9 2007-07-21       drh:      flag_alternateform = flag_altform2 = flag_zeropad = 0;
dbda8d6ce9 2007-07-21       drh:     done = 0;
dbda8d6ce9 2007-07-21       drh:     do{
dbda8d6ce9 2007-07-21       drh:       switch( c ){
dbda8d6ce9 2007-07-21       drh:         case '-':   flag_leftjustify = 1;     break;
dbda8d6ce9 2007-07-21       drh:         case '+':   flag_plussign = 1;        break;
dbda8d6ce9 2007-07-21       drh:         case ' ':   flag_blanksign = 1;       break;
dbda8d6ce9 2007-07-21       drh:         case '#':   flag_alternateform = 1;   break;
dbda8d6ce9 2007-07-21       drh:         case '!':   flag_altform2 = 1;        break;
dbda8d6ce9 2007-07-21       drh:         case '0':   flag_zeropad = 1;         break;
dbda8d6ce9 2007-07-21       drh:         default:    done = 1;                 break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }while( !done && (c=(*++fmt))!=0 );
dbda8d6ce9 2007-07-21       drh:     /* Get the field width */
dbda8d6ce9 2007-07-21       drh:     width = 0;
dbda8d6ce9 2007-07-21       drh:     if( c=='*' ){
dbda8d6ce9 2007-07-21       drh:       width = va_arg(ap,int);
dbda8d6ce9 2007-07-21       drh:       if( width<0 ){
dbda8d6ce9 2007-07-21       drh:         flag_leftjustify = 1;
dbda8d6ce9 2007-07-21       drh:         width = -width;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       c = *++fmt;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       while( c>='0' && c<='9' ){
dbda8d6ce9 2007-07-21       drh:         width = width*10 + c - '0';
dbda8d6ce9 2007-07-21       drh:         c = *++fmt;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( width > etBUFSIZE-10 ){
dbda8d6ce9 2007-07-21       drh:       width = etBUFSIZE-10;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     /* Get the precision */
dbda8d6ce9 2007-07-21       drh:     if( c=='.' ){
dbda8d6ce9 2007-07-21       drh:       precision = 0;
dbda8d6ce9 2007-07-21       drh:       c = *++fmt;
dbda8d6ce9 2007-07-21       drh:       if( c=='*' ){
dbda8d6ce9 2007-07-21       drh:         precision = va_arg(ap,int);
dbda8d6ce9 2007-07-21       drh:         if( precision<0 ) precision = -precision;
dbda8d6ce9 2007-07-21       drh:         c = *++fmt;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         while( c>='0' && c<='9' ){
dbda8d6ce9 2007-07-21       drh:           precision = precision*10 + c - '0';
dbda8d6ce9 2007-07-21       drh:           c = *++fmt;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       precision = -1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     /* Get the conversion type modifier */
dbda8d6ce9 2007-07-21       drh:     if( c=='l' ){
dbda8d6ce9 2007-07-21       drh:       flag_long = 1;
dbda8d6ce9 2007-07-21       drh:       c = *++fmt;
dbda8d6ce9 2007-07-21       drh:       if( c=='l' ){
dbda8d6ce9 2007-07-21       drh:         flag_longlong = 1;
dbda8d6ce9 2007-07-21       drh:         c = *++fmt;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         flag_longlong = 0;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       flag_long = flag_longlong = 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     /* Fetch the info entry for the field */
dbda8d6ce9 2007-07-21       drh:     infop = 0;
dbda8d6ce9 2007-07-21       drh:     xtype = etERROR;
dbda8d6ce9 2007-07-21       drh:     for(idx=0; idx<etNINFO; idx++){
dbda8d6ce9 2007-07-21       drh:       if( c==fmtinfo[idx].fmttype ){
dbda8d6ce9 2007-07-21       drh:         infop = &fmtinfo[idx];
dbda8d6ce9 2007-07-21       drh:         xtype = infop->type;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     zExtra = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     /* Limit the precision to prevent overflowing buf[] during conversion */
dbda8d6ce9 2007-07-21       drh:     if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
dbda8d6ce9 2007-07-21       drh:       precision = etBUFSIZE-40;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** At this point, variables are initialized as follows:
dbda8d6ce9 2007-07-21       drh:     **
dbda8d6ce9 2007-07-21       drh:     **   flag_alternateform          TRUE if a '#' is present.
dbda8d6ce9 2007-07-21       drh:     **   flag_altform2               TRUE if a '!' is present.
dbda8d6ce9 2007-07-21       drh:     **   flag_plussign               TRUE if a '+' is present.
dbda8d6ce9 2007-07-21       drh:     **   flag_leftjustify            TRUE if a '-' is present or if the
dbda8d6ce9 2007-07-21       drh:     **                               field width was negative.
dbda8d6ce9 2007-07-21       drh:     **   flag_zeropad                TRUE if the width began with 0.
dbda8d6ce9 2007-07-21       drh:     **   flag_long                   TRUE if the letter 'l' (ell) prefixed
dbda8d6ce9 2007-07-21       drh:     **                               the conversion character.
dbda8d6ce9 2007-07-21       drh:     **   flag_longlong               TRUE if the letter 'll' (ell ell) prefixed
dbda8d6ce9 2007-07-21       drh:     **                               the conversion character.
dbda8d6ce9 2007-07-21       drh:     **   flag_blanksign              TRUE if a ' ' is present.
dbda8d6ce9 2007-07-21       drh:     **   width                       The specified field width.  This is
dbda8d6ce9 2007-07-21       drh:     **                               always non-negative.  Zero is the default.
dbda8d6ce9 2007-07-21       drh:     **   precision                   The specified precision.  The default
dbda8d6ce9 2007-07-21       drh:     **                               is -1.
dbda8d6ce9 2007-07-21       drh:     **   xtype                       The class of the conversion.
dbda8d6ce9 2007-07-21       drh:     **   infop                       Pointer to the appropriate info struct.
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     switch( xtype ){
dbda8d6ce9 2007-07-21       drh:       case etPOINTER:
dbda8d6ce9 2007-07-21       drh:         flag_longlong = sizeof(char*)==sizeof(i64);
dbda8d6ce9 2007-07-21       drh:         flag_long = sizeof(char*)==sizeof(long int);
dbda8d6ce9 2007-07-21       drh:         /* Fall through into the next case */
dbda8d6ce9 2007-07-21       drh:       case etRADIX:
dbda8d6ce9 2007-07-21       drh:         if( infop->flags & FLAG_SIGNED ){
dbda8d6ce9 2007-07-21       drh:           i64 v;
dbda8d6ce9 2007-07-21       drh:           if( flag_longlong )   v = va_arg(ap,i64);
dbda8d6ce9 2007-07-21       drh:           else if( flag_long )  v = va_arg(ap,long int);
dbda8d6ce9 2007-07-21       drh:           else                  v = va_arg(ap,int);
dbda8d6ce9 2007-07-21       drh:           if( v<0 ){
dbda8d6ce9 2007-07-21       drh:             longvalue = -v;
dbda8d6ce9 2007-07-21       drh:             prefix = '-';
dbda8d6ce9 2007-07-21       drh:           }else{
dbda8d6ce9 2007-07-21       drh:             longvalue = v;
dbda8d6ce9 2007-07-21       drh:             if( flag_plussign )        prefix = '+';
dbda8d6ce9 2007-07-21       drh:             else if( flag_blanksign )  prefix = ' ';
dbda8d6ce9 2007-07-21       drh:             else                       prefix = 0;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           if( flag_longlong )   longvalue = va_arg(ap,u64);
dbda8d6ce9 2007-07-21       drh:           else if( flag_long )  longvalue = va_arg(ap,unsigned long int);
dbda8d6ce9 2007-07-21       drh:           else                  longvalue = va_arg(ap,unsigned int);
dbda8d6ce9 2007-07-21       drh:           prefix = 0;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( longvalue==0 ) flag_alternateform = 0;
dbda8d6ce9 2007-07-21       drh:         if( flag_zeropad && precision<width-(prefix!=0) ){
dbda8d6ce9 2007-07-21       drh:           precision = width-(prefix!=0);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         bufpt = &buf[etBUFSIZE-1];
dbda8d6ce9 2007-07-21       drh:         {
dbda8d6ce9 2007-07-21       drh:           register const char *cset;      /* Use registers for speed */
dbda8d6ce9 2007-07-21       drh:           register int base;
dbda8d6ce9 2007-07-21       drh:           cset = &aDigits[infop->charset];
dbda8d6ce9 2007-07-21       drh:           base = infop->base;
dbda8d6ce9 2007-07-21       drh:           do{                                           /* Convert to ascii */
dbda8d6ce9 2007-07-21       drh:             *(--bufpt) = cset[longvalue%base];
dbda8d6ce9 2007-07-21       drh:             longvalue = longvalue/base;
dbda8d6ce9 2007-07-21       drh:           }while( longvalue>0 );
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         length = &buf[etBUFSIZE-1]-bufpt;
dbda8d6ce9 2007-07-21       drh:         for(idx=precision-length; idx>0; idx--){
dbda8d6ce9 2007-07-21       drh:           *(--bufpt) = '0';                             /* Zero pad */
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
dbda8d6ce9 2007-07-21       drh:         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
dbda8d6ce9 2007-07-21       drh:           const char *pre;
dbda8d6ce9 2007-07-21       drh:           char x;
dbda8d6ce9 2007-07-21       drh:           pre = &aPrefix[infop->prefix];
dbda8d6ce9 2007-07-21       drh:           if( *bufpt!=pre[0] ){
dbda8d6ce9 2007-07-21       drh:             for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         length = &buf[etBUFSIZE-1]-bufpt;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case etFLOAT:
dbda8d6ce9 2007-07-21       drh:       case etEXP:
dbda8d6ce9 2007-07-21       drh:       case etGENERIC:
dbda8d6ce9 2007-07-21       drh:         realvalue = va_arg(ap,double);
dbda8d6ce9 2007-07-21       drh:         if( precision<0 ) precision = 6;         /* Set default precision */
dbda8d6ce9 2007-07-21       drh:         if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
dbda8d6ce9 2007-07-21       drh:         if( realvalue<0.0 ){
dbda8d6ce9 2007-07-21       drh:           realvalue = -realvalue;
dbda8d6ce9 2007-07-21       drh:           prefix = '-';
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           if( flag_plussign )          prefix = '+';
dbda8d6ce9 2007-07-21       drh:           else if( flag_blanksign )    prefix = ' ';
dbda8d6ce9 2007-07-21       drh:           else                         prefix = 0;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( xtype==etGENERIC && precision>0 ) precision--;
dbda8d6ce9 2007-07-21       drh: #if 0
dbda8d6ce9 2007-07-21       drh:         /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
dbda8d6ce9 2007-07-21       drh:         for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
dbda8d6ce9 2007-07-21       drh: #else
dbda8d6ce9 2007-07-21       drh:         /* It makes more sense to use 0.5 */
dbda8d6ce9 2007-07-21       drh:         for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:         if( xtype==etFLOAT ) realvalue += rounder;
dbda8d6ce9 2007-07-21       drh:         /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
dbda8d6ce9 2007-07-21       drh:         exp = 0;
dbda8d6ce9 2007-07-21       drh:         if( realvalue>0.0 ){
dbda8d6ce9 2007-07-21       drh:           while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
dbda8d6ce9 2007-07-21       drh:           while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
dbda8d6ce9 2007-07-21       drh:           while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
dbda8d6ce9 2007-07-21       drh:           while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
dbda8d6ce9 2007-07-21       drh:           while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
dbda8d6ce9 2007-07-21       drh:           if( exp>350 || exp<-350 ){
dbda8d6ce9 2007-07-21       drh:             bufpt = "NaN";
dbda8d6ce9 2007-07-21       drh:             length = 3;
dbda8d6ce9 2007-07-21       drh:             break;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         bufpt = buf;
dbda8d6ce9 2007-07-21       drh:         /*
dbda8d6ce9 2007-07-21       drh:         ** If the field type is etGENERIC, then convert to either etEXP
dbda8d6ce9 2007-07-21       drh:         ** or etFLOAT, as appropriate.
dbda8d6ce9 2007-07-21       drh:         */
dbda8d6ce9 2007-07-21       drh:         flag_exp = xtype==etEXP;
dbda8d6ce9 2007-07-21       drh:         if( xtype!=etFLOAT ){
dbda8d6ce9 2007-07-21       drh:           realvalue += rounder;
dbda8d6ce9 2007-07-21       drh:           if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( xtype==etGENERIC ){
dbda8d6ce9 2007-07-21       drh:           flag_rtz = !flag_alternateform;
dbda8d6ce9 2007-07-21       drh:           if( exp<-4 || exp>precision ){
dbda8d6ce9 2007-07-21       drh:             xtype = etEXP;
dbda8d6ce9 2007-07-21       drh:           }else{
dbda8d6ce9 2007-07-21       drh:             precision = precision - exp;
dbda8d6ce9 2007-07-21       drh:             xtype = etFLOAT;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           flag_rtz = 0;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( xtype==etEXP ){
dbda8d6ce9 2007-07-21       drh:           e2 = 0;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           e2 = exp;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         nsd = 0;
dbda8d6ce9 2007-07-21       drh:         flag_dp = (precision>0) | flag_alternateform | flag_altform2;
dbda8d6ce9 2007-07-21       drh:         /* The sign in front of the number */
dbda8d6ce9 2007-07-21       drh:         if( prefix ){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = prefix;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* Digits prior to the decimal point */
dbda8d6ce9 2007-07-21       drh:         if( e2<0 ){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = '0';
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           for(; e2>=0; e2--){
dbda8d6ce9 2007-07-21       drh:             *(bufpt++) = et_getdigit(&realvalue,&nsd);
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* The decimal point */
dbda8d6ce9 2007-07-21       drh:         if( flag_dp ){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = '.';
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* "0" digits after the decimal point but before the first
dbda8d6ce9 2007-07-21       drh:         ** significant digit of the number */
dbda8d6ce9 2007-07-21       drh:         for(e2++; e2<0 && precision>0; precision--, e2++){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = '0';
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* Significant digits after the decimal point */
dbda8d6ce9 2007-07-21       drh:         while( (precision--)>0 ){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = et_getdigit(&realvalue,&nsd);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* Remove trailing zeros and the "." if no digits follow the "." */
dbda8d6ce9 2007-07-21       drh:         if( flag_rtz && flag_dp ){
dbda8d6ce9 2007-07-21       drh:           while( bufpt[-1]=='0' ) *(--bufpt) = 0;
dbda8d6ce9 2007-07-21       drh:           assert( bufpt>buf );
dbda8d6ce9 2007-07-21       drh:           if( bufpt[-1]=='.' ){
dbda8d6ce9 2007-07-21       drh:             if( flag_altform2 ){
dbda8d6ce9 2007-07-21       drh:               *(bufpt++) = '0';
dbda8d6ce9 2007-07-21       drh:             }else{
dbda8d6ce9 2007-07-21       drh:               *(--bufpt) = 0;
dbda8d6ce9 2007-07-21       drh:             }
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* Add the "eNNN" suffix */
dbda8d6ce9 2007-07-21       drh:         if( flag_exp || (xtype==etEXP && exp) ){
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = aDigits[infop->charset];
dbda8d6ce9 2007-07-21       drh:           if( exp<0 ){
dbda8d6ce9 2007-07-21       drh:             *(bufpt++) = '-'; exp = -exp;
dbda8d6ce9 2007-07-21       drh:           }else{
dbda8d6ce9 2007-07-21       drh:             *(bufpt++) = '+';
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           if( exp>=100 ){
dbda8d6ce9 2007-07-21       drh:             *(bufpt++) = (exp/100)+'0';                /* 100's digit */
dbda8d6ce9 2007-07-21       drh:             exp %= 100;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = exp/10+'0';                     /* 10's digit */
dbda8d6ce9 2007-07-21       drh:           *(bufpt++) = exp%10+'0';                     /* 1's digit */
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         *bufpt = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:         /* The converted number is in buf[] and zero terminated. Output it.
dbda8d6ce9 2007-07-21       drh:         ** Note that the number is in the usual order, not reversed as with
dbda8d6ce9 2007-07-21       drh:         ** integer conversions. */
dbda8d6ce9 2007-07-21       drh:         length = bufpt-buf;
dbda8d6ce9 2007-07-21       drh:         bufpt = buf;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:         /* Special case:  Add leading zeros if the flag_zeropad flag is
dbda8d6ce9 2007-07-21       drh:         ** set and we are not left justified */
dbda8d6ce9 2007-07-21       drh:         if( flag_zeropad && !flag_leftjustify && length < width){
dbda8d6ce9 2007-07-21       drh:           int i;
dbda8d6ce9 2007-07-21       drh:           int nPad = width - length;
dbda8d6ce9 2007-07-21       drh:           for(i=width; i>=nPad; i--){
dbda8d6ce9 2007-07-21       drh:             bufpt[i] = bufpt[i-nPad];
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           i = prefix!=0;
dbda8d6ce9 2007-07-21       drh:           while( nPad-- ) bufpt[i++] = '0';
dbda8d6ce9 2007-07-21       drh:           length = width;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case etSIZE:
dbda8d6ce9 2007-07-21       drh:         *(va_arg(ap,int*)) = count;
dbda8d6ce9 2007-07-21       drh:         length = width = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case etPERCENT:
dbda8d6ce9 2007-07-21       drh:         buf[0] = '%';
dbda8d6ce9 2007-07-21       drh:         bufpt = buf;
dbda8d6ce9 2007-07-21       drh:         length = 1;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case etCHARX:
dbda8d6ce9 2007-07-21       drh:         c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 ){
dbda8d6ce9 2007-07-21       drh:           for(idx=1; idx<precision; idx++) buf[idx] = c;
dbda8d6ce9 2007-07-21       drh:           length = precision;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           length =1;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         bufpt = buf;
dbda8d6ce9 2007-07-21       drh:         break;
c7278fd013 2007-09-22       jnc:       case etPATH: {
c7278fd013 2007-09-22       jnc:         int i;
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
c7278fd013 2007-09-22       jnc:         char *e = va_arg(ap,char*);
c7278fd013 2007-09-22       jnc:         if( e==0 ){e="";}
9a8fdf7294 2009-12-18       drh:         length = StrNLen32(e, limit);
c7278fd013 2007-09-22       jnc:         zExtra = bufpt = malloc(length+1);
c7278fd013 2007-09-22       jnc:         for( i=0; i<length; i++ ){
c7278fd013 2007-09-22       jnc:           if( e[i]=='\\' ){
c7278fd013 2007-09-22       jnc:             bufpt[i]='/';
c7278fd013 2007-09-22       jnc:           }else{
c7278fd013 2007-09-22       jnc:             bufpt[i]=e[i];
c7278fd013 2007-09-22       jnc:           }
c7278fd013 2007-09-22       jnc:         }
c7278fd013 2007-09-22       jnc:         bufpt[length]='\0';
c7278fd013 2007-09-22       jnc:         break;
c7278fd013 2007-09-22       jnc:       }
dbda8d6ce9 2007-07-21       drh:       case etSTRING:
8c3ec00311 2008-02-04       drh:       case etDYNSTRING: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         bufpt = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         if( bufpt==0 ){
dbda8d6ce9 2007-07-21       drh:           bufpt = "";
dbda8d6ce9 2007-07-21       drh:         }else if( xtype==etDYNSTRING ){
dbda8d6ce9 2007-07-21       drh:           zExtra = bufpt;
dbda8d6ce9 2007-07-21       drh:         }
9a8fdf7294 2009-12-18       drh:         length = StrNLen32(bufpt, limit);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
dbda8d6ce9 2007-07-21       drh:         break;
8c3ec00311 2008-02-04       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etBLOB: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap, int) : -1;
dbda8d6ce9 2007-07-21       drh:         Blob *pBlob = va_arg(ap, Blob*);
dbda8d6ce9 2007-07-21       drh:         bufpt = blob_buffer(pBlob);
dbda8d6ce9 2007-07-21       drh:         length = blob_size(pBlob);
8c3ec00311 2008-02-04       drh:         if( limit>=0 && limit<length ) length = limit;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etBLOBSQL: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap, int) : -1;
dbda8d6ce9 2007-07-21       drh:         Blob *pBlob = va_arg(ap, Blob*);
dbda8d6ce9 2007-07-21       drh:         char *zOrig = blob_buffer(pBlob);
dbda8d6ce9 2007-07-21       drh:         int i, j, n, cnt;
dbda8d6ce9 2007-07-21       drh:         n = blob_size(pBlob);
8c3ec00311 2008-02-04       drh:         if( limit>=0 && limit<n ) n = limit;
dbda8d6ce9 2007-07-21       drh:         for(cnt=i=0; i<n; i++){ if( zOrig[i]=='\'' ) cnt++; }
dbda8d6ce9 2007-07-21       drh:         if( n+cnt+2 > etBUFSIZE ){
dbda8d6ce9 2007-07-21       drh:           bufpt = zExtra = malloc( n + cnt + 2 );
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           bufpt = buf;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         bufpt[0] = '\'';
dbda8d6ce9 2007-07-21       drh:         for(i=0, j=1; i<n; i++, j++){
dbda8d6ce9 2007-07-21       drh:           if( zOrig[i]=='\'' ){ bufpt[j++] = '\''; }
dbda8d6ce9 2007-07-21       drh:           bufpt[j] = zOrig[i];
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         bufpt[j++] = '\'';
dbda8d6ce9 2007-07-21       drh:         length = j;
dbda8d6ce9 2007-07-21       drh:         assert( length==n+cnt+2 );
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etSQLESCAPE:
dbda8d6ce9 2007-07-21       drh:       case etSQLESCAPE2: {
dbda8d6ce9 2007-07-21       drh:         int i, j, n, ch, isnull;
dbda8d6ce9 2007-07-21       drh:         int needQuote;
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         char *escarg = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         isnull = escarg==0;
dbda8d6ce9 2007-07-21       drh:         if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
8c3ec00311 2008-02-04       drh:         if( limit<0 ) limit = strlen(escarg);
8c3ec00311 2008-02-04       drh:         for(i=n=0; i<limit; i++){
8c3ec00311 2008-02-04       drh:           if( escarg[i]=='\'' )  n++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         needQuote = !isnull && xtype==etSQLESCAPE2;
dbda8d6ce9 2007-07-21       drh:         n += i + 1 + needQuote*2;
dbda8d6ce9 2007-07-21       drh:         if( n>etBUFSIZE ){
dbda8d6ce9 2007-07-21       drh:           bufpt = zExtra = malloc( n );
dbda8d6ce9 2007-07-21       drh:           if( bufpt==0 ) return -1;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           bufpt = buf;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         j = 0;
dbda8d6ce9 2007-07-21       drh:         if( needQuote ) bufpt[j++] = '\'';
8c3ec00311 2008-02-04       drh:         for(i=0; i<limit; i++){
8c3ec00311 2008-02-04       drh:           bufpt[j++] = ch = escarg[i];
dbda8d6ce9 2007-07-21       drh:           if( ch=='\'' ) bufpt[j++] = ch;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( needQuote ) bufpt[j++] = '\'';
dbda8d6ce9 2007-07-21       drh:         bufpt[j] = 0;
dbda8d6ce9 2007-07-21       drh:         length = j;
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etHTMLIZE: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         char *zMem = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         if( zMem==0 ) zMem = "";
8c3ec00311 2008-02-04       drh:         zExtra = bufpt = htmlize(zMem, limit);
dbda8d6ce9 2007-07-21       drh:         length = strlen(bufpt);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etHTTPIZE: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         char *zMem = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         if( zMem==0 ) zMem = "";
8c3ec00311 2008-02-04       drh:         zExtra = bufpt = httpize(zMem, limit);
dbda8d6ce9 2007-07-21       drh:         length = strlen(bufpt);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etURLIZE: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         char *zMem = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         if( zMem==0 ) zMem = "";
8c3ec00311 2008-02-04       drh:         zExtra = bufpt = urlize(zMem, limit);
dbda8d6ce9 2007-07-21       drh:         length = strlen(bufpt);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etFOSSILIZE: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
dbda8d6ce9 2007-07-21       drh:         char *zMem = va_arg(ap,char*);
dbda8d6ce9 2007-07-21       drh:         if( zMem==0 ) zMem = "";
8c3ec00311 2008-02-04       drh:         zExtra = bufpt = fossilize(zMem, limit);
dbda8d6ce9 2007-07-21       drh:         length = strlen(bufpt);
dbda8d6ce9 2007-07-21       drh:         if( precision>=0 && precision<length ) length = precision;
2859293737 2007-11-22       drh:         break;
2859293737 2007-11-22       drh:       }
2859293737 2007-11-22       drh:       case etWIKISTR: {
8c3ec00311 2008-02-04       drh:         int limit = flag_alternateform ? va_arg(ap,int) : -1;
2859293737 2007-11-22       drh:         char *zWiki = va_arg(ap, char*);
2859293737 2007-11-22       drh:         Blob wiki;
8c3ec00311 2008-02-04       drh:         blob_init(&wiki, zWiki, limit);
2859293737 2007-11-22       drh:         wiki_convert(&wiki, pBlob, WIKI_INLINE);
2859293737 2007-11-22       drh:         blob_reset(&wiki);
2859293737 2007-11-22       drh:         length = width = 0;
2859293737 2007-11-22       drh:         break;
2859293737 2007-11-22       drh:       }
2859293737 2007-11-22       drh:       case etWIKIBLOB: {
2859293737 2007-11-22       drh:         Blob *pWiki = va_arg(ap, Blob*);
2859293737 2007-11-22       drh:         wiki_convert(pWiki, pBlob, WIKI_INLINE);
2859293737 2007-11-22       drh:         length = width = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case etERROR:
dbda8d6ce9 2007-07-21       drh:         buf[0] = '%';
dbda8d6ce9 2007-07-21       drh:         buf[1] = c;
dbda8d6ce9 2007-07-21       drh:         errorflag = 0;
dbda8d6ce9 2007-07-21       drh:         idx = 1+(c!=0);
2859293737 2007-11-22       drh:         blob_append(pBlob,"%",idx);
dbda8d6ce9 2007-07-21       drh:         count += idx;
dbda8d6ce9 2007-07-21       drh:         if( c==0 ) fmt--;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }/* End switch over the format type */
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** The text of the conversion is pointed to by "bufpt" and is
dbda8d6ce9 2007-07-21       drh:     ** "length" characters long.  The field width is "width".  Do
dbda8d6ce9 2007-07-21       drh:     ** the output.
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     if( !flag_leftjustify ){
dbda8d6ce9 2007-07-21       drh:       register int nspace;
dbda8d6ce9 2007-07-21       drh:       nspace = width-length;
dbda8d6ce9 2007-07-21       drh:       if( nspace>0 ){
dbda8d6ce9 2007-07-21       drh:         count += nspace;
dbda8d6ce9 2007-07-21       drh:         while( nspace>=etSPACESIZE ){
2859293737 2007-11-22       drh:           blob_append(pBlob,spaces,etSPACESIZE);
dbda8d6ce9 2007-07-21       drh:           nspace -= etSPACESIZE;
dbda8d6ce9 2007-07-21       drh:         }
2859293737 2007-11-22       drh:         if( nspace>0 ) blob_append(pBlob,spaces,nspace);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( length>0 ){
2859293737 2007-11-22       drh:       blob_append(pBlob,bufpt,length);
dbda8d6ce9 2007-07-21       drh:       count += length;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( flag_leftjustify ){
dbda8d6ce9 2007-07-21       drh:       register int nspace;
dbda8d6ce9 2007-07-21       drh:       nspace = width-length;
dbda8d6ce9 2007-07-21       drh:       if( nspace>0 ){
dbda8d6ce9 2007-07-21       drh:         count += nspace;
dbda8d6ce9 2007-07-21       drh:         while( nspace>=etSPACESIZE ){
2859293737 2007-11-22       drh:           blob_append(pBlob,spaces,etSPACESIZE);
dbda8d6ce9 2007-07-21       drh:           nspace -= etSPACESIZE;
dbda8d6ce9 2007-07-21       drh:         }
2859293737 2007-11-22       drh:         if( nspace>0 ) blob_append(pBlob,spaces,nspace);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( zExtra ){
dbda8d6ce9 2007-07-21       drh:       free(zExtra);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }/* End for loop over the format string */
dbda8d6ce9 2007-07-21       drh:   return errorflag ? -1 : count;
dbda8d6ce9 2007-07-21       drh: } /* End of function */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print into memory obtained from malloc().
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: char *mprintf(const char *zFormat, ...){
dbda8d6ce9 2007-07-21       drh:   va_list ap;
dbda8d6ce9 2007-07-21       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   va_start(ap,zFormat);
dbda8d6ce9 2007-07-21       drh:   z = vmprintf(zFormat, ap);
dbda8d6ce9 2007-07-21       drh:   va_end(ap);
dbda8d6ce9 2007-07-21       drh:   return z;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: char *vmprintf(const char *zFormat, va_list ap){
dbda8d6ce9 2007-07-21       drh:   Blob blob = empty_blob;
dbda8d6ce9 2007-07-21       drh:   blob_vappendf(&blob, zFormat, ap);
dbda8d6ce9 2007-07-21       drh:   blob_materialize(&blob);
dbda8d6ce9 2007-07-21       drh:   return blob.aData;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Record an error message in the global g.zErrMsg variable.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If there is already another error message, only overwrite it if
dbda8d6ce9 2007-07-21       drh: ** the current error has a higher priority.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void fossil_error(int iPriority, const char *zFormat, ...){
dbda8d6ce9 2007-07-21       drh:   va_list ap;
dbda8d6ce9 2007-07-21       drh:   if( iPriority<=0 ){
dbda8d6ce9 2007-07-21       drh:     return;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( g.zErrMsg ){
dbda8d6ce9 2007-07-21       drh:     if( g.iErrPriority>=iPriority ){
dbda8d6ce9 2007-07-21       drh:       return;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     free(g.zErrMsg);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   va_start(ap, zFormat);
dbda8d6ce9 2007-07-21       drh:   g.zErrMsg = vmprintf(zFormat, ap);
dbda8d6ce9 2007-07-21       drh:   va_end(ap);
dbda8d6ce9 2007-07-21       drh:   g.iErrPriority = iPriority;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: void fossil_error_reset(void){
dbda8d6ce9 2007-07-21       drh:   free(g.zErrMsg);
dbda8d6ce9 2007-07-21       drh:   g.zErrMsg = 0;
dbda8d6ce9 2007-07-21       drh:   g.iErrPriority = 0;
dbda8d6ce9 2007-07-21       drh: }