Annotation of embedaddon/php/ext/sqlite/libsqlite/src/printf.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** The "printf" code that follows dates from the 1980's. It is in
! 3: ** the public domain. The original comments are included here for
! 4: ** completeness. They are very out-of-date but might be useful as
! 5: ** an historical reference. Most of the "enhancements" have been backed
! 6: ** out so that the functionality is now the same as standard printf().
! 7: **
! 8: **************************************************************************
! 9: **
! 10: ** The following modules is an enhanced replacement for the "printf" subroutines
! 11: ** found in the standard C library. The following enhancements are
! 12: ** supported:
! 13: **
! 14: ** + Additional functions. The standard set of "printf" functions
! 15: ** includes printf, fprintf, sprintf, vprintf, vfprintf, and
! 16: ** vsprintf. This module adds the following:
! 17: **
! 18: ** * snprintf -- Works like sprintf, but has an extra argument
! 19: ** which is the size of the buffer written to.
! 20: **
! 21: ** * mprintf -- Similar to sprintf. Writes output to memory
! 22: ** obtained from malloc.
! 23: **
! 24: ** * xprintf -- Calls a function to dispose of output.
! 25: **
! 26: ** * nprintf -- No output, but returns the number of characters
! 27: ** that would have been output by printf.
! 28: **
! 29: ** * A v- version (ex: vsnprintf) of every function is also
! 30: ** supplied.
! 31: **
! 32: ** + A few extensions to the formatting notation are supported:
! 33: **
! 34: ** * The "=" flag (similar to "-") causes the output to be
! 35: ** be centered in the appropriately sized field.
! 36: **
! 37: ** * The %b field outputs an integer in binary notation.
! 38: **
! 39: ** * The %c field now accepts a precision. The character output
! 40: ** is repeated by the number of times the precision specifies.
! 41: **
! 42: ** * The %' field works like %c, but takes as its character the
! 43: ** next character of the format string, instead of the next
! 44: ** argument. For example, printf("%.78'-") prints 78 minus
! 45: ** signs, the same as printf("%.78c",'-').
! 46: **
! 47: ** + When compiled using GCC on a SPARC, this version of printf is
! 48: ** faster than the library printf for SUN OS 4.1.
! 49: **
! 50: ** + All functions are fully reentrant.
! 51: **
! 52: */
! 53: #include "sqliteInt.h"
! 54:
! 55: /*
! 56: ** Conversion types fall into various categories as defined by the
! 57: ** following enumeration.
! 58: */
! 59: #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
! 60: #define etFLOAT 2 /* Floating point. %f */
! 61: #define etEXP 3 /* Exponentional notation. %e and %E */
! 62: #define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
! 63: #define etSIZE 5 /* Return number of characters processed so far. %n */
! 64: #define etSTRING 6 /* Strings. %s */
! 65: #define etDYNSTRING 7 /* Dynamically allocated strings. %z */
! 66: #define etPERCENT 8 /* Percent symbol. %% */
! 67: #define etCHARX 9 /* Characters. %c */
! 68: #define etERROR 10 /* Used to indicate no such conversion type */
! 69: /* The rest are extensions, not normally found in printf() */
! 70: #define etCHARLIT 11 /* Literal characters. %' */
! 71: #define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
! 72: #define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
! 73: NULL pointers replaced by SQL NULL. %Q */
! 74: #define etTOKEN 14 /* a pointer to a Token structure */
! 75: #define etSRCLIST 15 /* a pointer to a SrcList */
! 76:
! 77:
! 78: /*
! 79: ** An "etByte" is an 8-bit unsigned value.
! 80: */
! 81: typedef unsigned char etByte;
! 82:
! 83: /*
! 84: ** Each builtin conversion character (ex: the 'd' in "%d") is described
! 85: ** by an instance of the following structure
! 86: */
! 87: typedef struct et_info { /* Information about each format field */
! 88: char fmttype; /* The format field code letter */
! 89: etByte base; /* The base for radix conversion */
! 90: etByte flags; /* One or more of FLAG_ constants below */
! 91: etByte type; /* Conversion paradigm */
! 92: char *charset; /* The character set for conversion */
! 93: char *prefix; /* Prefix on non-zero values in alt format */
! 94: } et_info;
! 95:
! 96: /*
! 97: ** Allowed values for et_info.flags
! 98: */
! 99: #define FLAG_SIGNED 1 /* True if the value to convert is signed */
! 100: #define FLAG_INTERN 2 /* True if for internal use only */
! 101:
! 102:
! 103: /*
! 104: ** The following table is searched linearly, so it is good to put the
! 105: ** most frequently used conversion types first.
! 106: */
! 107: static et_info fmtinfo[] = {
! 108: { 'd', 10, 1, etRADIX, "0123456789", 0 },
! 109: { 's', 0, 0, etSTRING, 0, 0 },
! 110: { 'z', 0, 2, etDYNSTRING, 0, 0 },
! 111: { 'q', 0, 0, etSQLESCAPE, 0, 0 },
! 112: { 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
! 113: { 'c', 0, 0, etCHARX, 0, 0 },
! 114: { 'o', 8, 0, etRADIX, "01234567", "0" },
! 115: { 'u', 10, 0, etRADIX, "0123456789", 0 },
! 116: { 'x', 16, 0, etRADIX, "0123456789abcdef", "x0" },
! 117: { 'X', 16, 0, etRADIX, "0123456789ABCDEF", "X0" },
! 118: { 'f', 0, 1, etFLOAT, 0, 0 },
! 119: { 'e', 0, 1, etEXP, "e", 0 },
! 120: { 'E', 0, 1, etEXP, "E", 0 },
! 121: { 'g', 0, 1, etGENERIC, "e", 0 },
! 122: { 'G', 0, 1, etGENERIC, "E", 0 },
! 123: { 'i', 10, 1, etRADIX, "0123456789", 0 },
! 124: { 'n', 0, 0, etSIZE, 0, 0 },
! 125: { '%', 0, 0, etPERCENT, 0, 0 },
! 126: { 'p', 10, 0, etRADIX, "0123456789", 0 },
! 127: { 'T', 0, 2, etTOKEN, 0, 0 },
! 128: { 'S', 0, 2, etSRCLIST, 0, 0 },
! 129: };
! 130: #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
! 131:
! 132: /*
! 133: ** If NOFLOATINGPOINT is defined, then none of the floating point
! 134: ** conversions will work.
! 135: */
! 136: #ifndef etNOFLOATINGPOINT
! 137: /*
! 138: ** "*val" is a double such that 0.1 <= *val < 10.0
! 139: ** Return the ascii code for the leading digit of *val, then
! 140: ** multiply "*val" by 10.0 to renormalize.
! 141: **
! 142: ** Example:
! 143: ** input: *val = 3.14159
! 144: ** output: *val = 1.4159 function return = '3'
! 145: **
! 146: ** The counter *cnt is incremented each time. After counter exceeds
! 147: ** 16 (the number of significant digits in a 64-bit float) '0' is
! 148: ** always returned.
! 149: */
! 150: static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
! 151: int digit;
! 152: LONGDOUBLE_TYPE d;
! 153: if( (*cnt)++ >= 16 ) return '0';
! 154: digit = (int)*val;
! 155: d = digit;
! 156: digit += '0';
! 157: *val = (*val - d)*10.0;
! 158: return digit;
! 159: }
! 160: #endif
! 161:
! 162: #define etBUFSIZE 1000 /* Size of the output buffer */
! 163:
! 164: /*
! 165: ** The root program. All variations call this core.
! 166: **
! 167: ** INPUTS:
! 168: ** func This is a pointer to a function taking three arguments
! 169: ** 1. A pointer to anything. Same as the "arg" parameter.
! 170: ** 2. A pointer to the list of characters to be output
! 171: ** (Note, this list is NOT null terminated.)
! 172: ** 3. An integer number of characters to be output.
! 173: ** (Note: This number might be zero.)
! 174: **
! 175: ** arg This is the pointer to anything which will be passed as the
! 176: ** first argument to "func". Use it for whatever you like.
! 177: **
! 178: ** fmt This is the format string, as in the usual print.
! 179: **
! 180: ** ap This is a pointer to a list of arguments. Same as in
! 181: ** vfprint.
! 182: **
! 183: ** OUTPUTS:
! 184: ** The return value is the total number of characters sent to
! 185: ** the function "func". Returns -1 on a error.
! 186: **
! 187: ** Note that the order in which automatic variables are declared below
! 188: ** seems to make a big difference in determining how fast this beast
! 189: ** will run.
! 190: */
! 191: static int vxprintf(
! 192: void (*func)(void*,const char*,int), /* Consumer of text */
! 193: void *arg, /* First argument to the consumer */
! 194: int useExtended, /* Allow extended %-conversions */
! 195: const char *fmt, /* Format string */
! 196: va_list ap /* arguments */
! 197: ){
! 198: int c; /* Next character in the format string */
! 199: char *bufpt; /* Pointer to the conversion buffer */
! 200: int precision; /* Precision of the current field */
! 201: int length; /* Length of the field */
! 202: int idx; /* A general purpose loop counter */
! 203: int count; /* Total number of characters output */
! 204: int width; /* Width of the current field */
! 205: etByte flag_leftjustify; /* True if "-" flag is present */
! 206: etByte flag_plussign; /* True if "+" flag is present */
! 207: etByte flag_blanksign; /* True if " " flag is present */
! 208: etByte flag_alternateform; /* True if "#" flag is present */
! 209: etByte flag_zeropad; /* True if field width constant starts with zero */
! 210: etByte flag_long; /* True if "l" flag is present */
! 211: unsigned long longvalue; /* Value for integer types */
! 212: LONGDOUBLE_TYPE realvalue; /* Value for real types */
! 213: et_info *infop; /* Pointer to the appropriate info structure */
! 214: char buf[etBUFSIZE]; /* Conversion buffer */
! 215: char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
! 216: etByte errorflag = 0; /* True if an error is encountered */
! 217: etByte xtype; /* Conversion paradigm */
! 218: char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
! 219: static char spaces[] = " ";
! 220: #define etSPACESIZE (sizeof(spaces)-1)
! 221: #ifndef etNOFLOATINGPOINT
! 222: int exp; /* exponent of real numbers */
! 223: double rounder; /* Used for rounding floating point values */
! 224: etByte flag_dp; /* True if decimal point should be shown */
! 225: etByte flag_rtz; /* True if trailing zeros should be removed */
! 226: etByte flag_exp; /* True to force display of the exponent */
! 227: int nsd; /* Number of significant digits returned */
! 228: #endif
! 229:
! 230: func(arg,"",0);
! 231: count = length = 0;
! 232: bufpt = 0;
! 233: for(; (c=(*fmt))!=0; ++fmt){
! 234: if( c!='%' ){
! 235: int amt;
! 236: bufpt = (char *)fmt;
! 237: amt = 1;
! 238: while( (c=(*++fmt))!='%' && c!=0 ) amt++;
! 239: (*func)(arg,bufpt,amt);
! 240: count += amt;
! 241: if( c==0 ) break;
! 242: }
! 243: if( (c=(*++fmt))==0 ){
! 244: errorflag = 1;
! 245: (*func)(arg,"%",1);
! 246: count++;
! 247: break;
! 248: }
! 249: /* Find out what flags are present */
! 250: flag_leftjustify = flag_plussign = flag_blanksign =
! 251: flag_alternateform = flag_zeropad = 0;
! 252: do{
! 253: switch( c ){
! 254: case '-': flag_leftjustify = 1; c = 0; break;
! 255: case '+': flag_plussign = 1; c = 0; break;
! 256: case ' ': flag_blanksign = 1; c = 0; break;
! 257: case '#': flag_alternateform = 1; c = 0; break;
! 258: case '0': flag_zeropad = 1; c = 0; break;
! 259: default: break;
! 260: }
! 261: }while( c==0 && (c=(*++fmt))!=0 );
! 262: /* Get the field width */
! 263: width = 0;
! 264: if( c=='*' ){
! 265: width = va_arg(ap,int);
! 266: if( width<0 ){
! 267: flag_leftjustify = 1;
! 268: width = -width;
! 269: }
! 270: c = *++fmt;
! 271: }else{
! 272: while( c>='0' && c<='9' ){
! 273: width = width*10 + c - '0';
! 274: c = *++fmt;
! 275: }
! 276: }
! 277: if( width > etBUFSIZE-10 ){
! 278: width = etBUFSIZE-10;
! 279: }
! 280: /* Get the precision */
! 281: if( c=='.' ){
! 282: precision = 0;
! 283: c = *++fmt;
! 284: if( c=='*' ){
! 285: precision = va_arg(ap,int);
! 286: if( precision<0 ) precision = -precision;
! 287: c = *++fmt;
! 288: }else{
! 289: while( c>='0' && c<='9' ){
! 290: precision = precision*10 + c - '0';
! 291: c = *++fmt;
! 292: }
! 293: }
! 294: /* Limit the precision to prevent overflowing buf[] during conversion */
! 295: if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
! 296: }else{
! 297: precision = -1;
! 298: }
! 299: /* Get the conversion type modifier */
! 300: if( c=='l' ){
! 301: flag_long = 1;
! 302: c = *++fmt;
! 303: }else{
! 304: flag_long = 0;
! 305: }
! 306: /* Fetch the info entry for the field */
! 307: infop = 0;
! 308: xtype = etERROR;
! 309: for(idx=0; idx<etNINFO; idx++){
! 310: if( c==fmtinfo[idx].fmttype ){
! 311: infop = &fmtinfo[idx];
! 312: if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
! 313: xtype = infop->type;
! 314: }
! 315: break;
! 316: }
! 317: }
! 318: zExtra = 0;
! 319:
! 320: /*
! 321: ** At this point, variables are initialized as follows:
! 322: **
! 323: ** flag_alternateform TRUE if a '#' is present.
! 324: ** flag_plussign TRUE if a '+' is present.
! 325: ** flag_leftjustify TRUE if a '-' is present or if the
! 326: ** field width was negative.
! 327: ** flag_zeropad TRUE if the width began with 0.
! 328: ** flag_long TRUE if the letter 'l' (ell) prefixed
! 329: ** the conversion character.
! 330: ** flag_blanksign TRUE if a ' ' is present.
! 331: ** width The specified field width. This is
! 332: ** always non-negative. Zero is the default.
! 333: ** precision The specified precision. The default
! 334: ** is -1.
! 335: ** xtype The class of the conversion.
! 336: ** infop Pointer to the appropriate info struct.
! 337: */
! 338: switch( xtype ){
! 339: case etRADIX:
! 340: if( flag_long ) longvalue = va_arg(ap,long);
! 341: else longvalue = va_arg(ap,int);
! 342: #if 1
! 343: /* For the format %#x, the value zero is printed "0" not "0x0".
! 344: ** I think this is stupid. */
! 345: if( longvalue==0 ) flag_alternateform = 0;
! 346: #else
! 347: /* More sensible: turn off the prefix for octal (to prevent "00"),
! 348: ** but leave the prefix for hex. */
! 349: if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
! 350: #endif
! 351: if( infop->flags & FLAG_SIGNED ){
! 352: if( *(long*)&longvalue<0 ){
! 353: longvalue = -*(long*)&longvalue;
! 354: prefix = '-';
! 355: }else if( flag_plussign ) prefix = '+';
! 356: else if( flag_blanksign ) prefix = ' ';
! 357: else prefix = 0;
! 358: }else prefix = 0;
! 359: if( flag_zeropad && precision<width-(prefix!=0) ){
! 360: precision = width-(prefix!=0);
! 361: }
! 362: bufpt = &buf[etBUFSIZE-1];
! 363: {
! 364: register char *cset; /* Use registers for speed */
! 365: register int base;
! 366: cset = infop->charset;
! 367: base = infop->base;
! 368: do{ /* Convert to ascii */
! 369: *(--bufpt) = cset[longvalue%base];
! 370: longvalue = longvalue/base;
! 371: }while( longvalue>0 );
! 372: }
! 373: length = &buf[etBUFSIZE-1]-bufpt;
! 374: for(idx=precision-length; idx>0; idx--){
! 375: *(--bufpt) = '0'; /* Zero pad */
! 376: }
! 377: if( prefix ) *(--bufpt) = prefix; /* Add sign */
! 378: if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
! 379: char *pre, x;
! 380: pre = infop->prefix;
! 381: if( *bufpt!=pre[0] ){
! 382: for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
! 383: }
! 384: }
! 385: length = &buf[etBUFSIZE-1]-bufpt;
! 386: break;
! 387: case etFLOAT:
! 388: case etEXP:
! 389: case etGENERIC:
! 390: realvalue = va_arg(ap,double);
! 391: #ifndef etNOFLOATINGPOINT
! 392: if( precision<0 ) precision = 6; /* Set default precision */
! 393: if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
! 394: if( realvalue<0.0 ){
! 395: realvalue = -realvalue;
! 396: prefix = '-';
! 397: }else{
! 398: if( flag_plussign ) prefix = '+';
! 399: else if( flag_blanksign ) prefix = ' ';
! 400: else prefix = 0;
! 401: }
! 402: if( infop->type==etGENERIC && precision>0 ) precision--;
! 403: rounder = 0.0;
! 404: #if 0
! 405: /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
! 406: for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
! 407: #else
! 408: /* It makes more sense to use 0.5 */
! 409: for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
! 410: #endif
! 411: if( infop->type==etFLOAT ) realvalue += rounder;
! 412: /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
! 413: exp = 0;
! 414: if( realvalue>0.0 ){
! 415: while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
! 416: while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
! 417: while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
! 418: while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
! 419: if( exp>350 || exp<-350 ){
! 420: bufpt = "NaN";
! 421: length = 3;
! 422: break;
! 423: }
! 424: }
! 425: bufpt = buf;
! 426: /*
! 427: ** If the field type is etGENERIC, then convert to either etEXP
! 428: ** or etFLOAT, as appropriate.
! 429: */
! 430: flag_exp = xtype==etEXP;
! 431: if( xtype!=etFLOAT ){
! 432: realvalue += rounder;
! 433: if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
! 434: }
! 435: if( xtype==etGENERIC ){
! 436: flag_rtz = !flag_alternateform;
! 437: if( exp<-4 || exp>precision ){
! 438: xtype = etEXP;
! 439: }else{
! 440: precision = precision - exp;
! 441: xtype = etFLOAT;
! 442: }
! 443: }else{
! 444: flag_rtz = 0;
! 445: }
! 446: /*
! 447: ** The "exp+precision" test causes output to be of type etEXP if
! 448: ** the precision is too large to fit in buf[].
! 449: */
! 450: nsd = 0;
! 451: if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
! 452: flag_dp = (precision>0 || flag_alternateform);
! 453: if( prefix ) *(bufpt++) = prefix; /* Sign */
! 454: if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
! 455: else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
! 456: if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
! 457: for(exp++; exp<0 && precision>0; precision--, exp++){
! 458: *(bufpt++) = '0';
! 459: }
! 460: while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
! 461: *(bufpt--) = 0; /* Null terminate */
! 462: if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
! 463: while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
! 464: if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
! 465: }
! 466: bufpt++; /* point to next free slot */
! 467: }else{ /* etEXP or etGENERIC */
! 468: flag_dp = (precision>0 || flag_alternateform);
! 469: if( prefix ) *(bufpt++) = prefix; /* Sign */
! 470: *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */
! 471: if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
! 472: while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
! 473: bufpt--; /* point to last digit */
! 474: if( flag_rtz && flag_dp ){ /* Remove tail zeros */
! 475: while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
! 476: if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
! 477: }
! 478: bufpt++; /* point to next free slot */
! 479: if( exp || flag_exp ){
! 480: *(bufpt++) = infop->charset[0];
! 481: if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
! 482: else { *(bufpt++) = '+'; }
! 483: if( exp>=100 ){
! 484: *(bufpt++) = (exp/100)+'0'; /* 100's digit */
! 485: exp %= 100;
! 486: }
! 487: *(bufpt++) = exp/10+'0'; /* 10's digit */
! 488: *(bufpt++) = exp%10+'0'; /* 1's digit */
! 489: }
! 490: }
! 491: /* The converted number is in buf[] and zero terminated. Output it.
! 492: ** Note that the number is in the usual order, not reversed as with
! 493: ** integer conversions. */
! 494: length = bufpt-buf;
! 495: bufpt = buf;
! 496:
! 497: /* Special case: Add leading zeros if the flag_zeropad flag is
! 498: ** set and we are not left justified */
! 499: if( flag_zeropad && !flag_leftjustify && length < width){
! 500: int i;
! 501: int nPad = width - length;
! 502: for(i=width; i>=nPad; i--){
! 503: bufpt[i] = bufpt[i-nPad];
! 504: }
! 505: i = prefix!=0;
! 506: while( nPad-- ) bufpt[i++] = '0';
! 507: length = width;
! 508: }
! 509: #endif
! 510: break;
! 511: case etSIZE:
! 512: *(va_arg(ap,int*)) = count;
! 513: length = width = 0;
! 514: break;
! 515: case etPERCENT:
! 516: buf[0] = '%';
! 517: bufpt = buf;
! 518: length = 1;
! 519: break;
! 520: case etCHARLIT:
! 521: case etCHARX:
! 522: c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
! 523: if( precision>=0 ){
! 524: for(idx=1; idx<precision; idx++) buf[idx] = c;
! 525: length = precision;
! 526: }else{
! 527: length =1;
! 528: }
! 529: bufpt = buf;
! 530: break;
! 531: case etSTRING:
! 532: case etDYNSTRING:
! 533: bufpt = va_arg(ap,char*);
! 534: if( bufpt==0 ){
! 535: bufpt = "";
! 536: }else if( xtype==etDYNSTRING ){
! 537: zExtra = bufpt;
! 538: }
! 539: length = strlen(bufpt);
! 540: if( precision>=0 && precision<length ) length = precision;
! 541: break;
! 542: case etSQLESCAPE:
! 543: case etSQLESCAPE2:
! 544: {
! 545: int i, j, n, c, isnull;
! 546: char *arg = va_arg(ap,char*);
! 547: isnull = arg==0;
! 548: if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
! 549: for(i=n=0; (c=arg[i])!=0; i++){
! 550: if( c=='\'' ) n++;
! 551: }
! 552: n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
! 553: if( n>etBUFSIZE ){
! 554: bufpt = zExtra = sqliteMalloc( n );
! 555: if( bufpt==0 ) return -1;
! 556: }else{
! 557: bufpt = buf;
! 558: }
! 559: j = 0;
! 560: if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
! 561: for(i=0; (c=arg[i])!=0; i++){
! 562: bufpt[j++] = c;
! 563: if( c=='\'' ) bufpt[j++] = c;
! 564: }
! 565: if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
! 566: bufpt[j] = 0;
! 567: length = j;
! 568: if( precision>=0 && precision<length ) length = precision;
! 569: }
! 570: break;
! 571: case etTOKEN: {
! 572: Token *pToken = va_arg(ap, Token*);
! 573: (*func)(arg, pToken->z, pToken->n);
! 574: length = width = 0;
! 575: break;
! 576: }
! 577: case etSRCLIST: {
! 578: SrcList *pSrc = va_arg(ap, SrcList*);
! 579: int k = va_arg(ap, int);
! 580: struct SrcList_item *pItem = &pSrc->a[k];
! 581: assert( k>=0 && k<pSrc->nSrc );
! 582: if( pItem->zDatabase && pItem->zDatabase[0] ){
! 583: (*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
! 584: (*func)(arg, ".", 1);
! 585: }
! 586: (*func)(arg, pItem->zName, strlen(pItem->zName));
! 587: length = width = 0;
! 588: break;
! 589: }
! 590: case etERROR:
! 591: buf[0] = '%';
! 592: buf[1] = c;
! 593: errorflag = 0;
! 594: idx = 1+(c!=0);
! 595: (*func)(arg,"%",idx);
! 596: count += idx;
! 597: if( c==0 ) fmt--;
! 598: break;
! 599: }/* End switch over the format type */
! 600: /*
! 601: ** The text of the conversion is pointed to by "bufpt" and is
! 602: ** "length" characters long. The field width is "width". Do
! 603: ** the output.
! 604: */
! 605: if( !flag_leftjustify ){
! 606: register int nspace;
! 607: nspace = width-length;
! 608: if( nspace>0 ){
! 609: count += nspace;
! 610: while( nspace>=etSPACESIZE ){
! 611: (*func)(arg,spaces,etSPACESIZE);
! 612: nspace -= etSPACESIZE;
! 613: }
! 614: if( nspace>0 ) (*func)(arg,spaces,nspace);
! 615: }
! 616: }
! 617: if( length>0 ){
! 618: (*func)(arg,bufpt,length);
! 619: count += length;
! 620: }
! 621: if( flag_leftjustify ){
! 622: register int nspace;
! 623: nspace = width-length;
! 624: if( nspace>0 ){
! 625: count += nspace;
! 626: while( nspace>=etSPACESIZE ){
! 627: (*func)(arg,spaces,etSPACESIZE);
! 628: nspace -= etSPACESIZE;
! 629: }
! 630: if( nspace>0 ) (*func)(arg,spaces,nspace);
! 631: }
! 632: }
! 633: if( zExtra ){
! 634: sqliteFree(zExtra);
! 635: }
! 636: }/* End for loop over the format string */
! 637: return errorflag ? -1 : count;
! 638: } /* End of function */
! 639:
! 640:
! 641: /* This structure is used to store state information about the
! 642: ** write to memory that is currently in progress.
! 643: */
! 644: struct sgMprintf {
! 645: char *zBase; /* A base allocation */
! 646: char *zText; /* The string collected so far */
! 647: int nChar; /* Length of the string so far */
! 648: int nTotal; /* Output size if unconstrained */
! 649: int nAlloc; /* Amount of space allocated in zText */
! 650: void *(*xRealloc)(void*,int); /* Function used to realloc memory */
! 651: };
! 652:
! 653: /*
! 654: ** This function implements the callback from vxprintf.
! 655: **
! 656: ** This routine add nNewChar characters of text in zNewText to
! 657: ** the sgMprintf structure pointed to by "arg".
! 658: */
! 659: static void mout(void *arg, const char *zNewText, int nNewChar){
! 660: struct sgMprintf *pM = (struct sgMprintf*)arg;
! 661: pM->nTotal += nNewChar;
! 662: if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
! 663: if( pM->xRealloc==0 ){
! 664: nNewChar = pM->nAlloc - pM->nChar - 1;
! 665: }else{
! 666: pM->nAlloc = pM->nChar + nNewChar*2 + 1;
! 667: if( pM->zText==pM->zBase ){
! 668: pM->zText = pM->xRealloc(0, pM->nAlloc);
! 669: if( pM->zText && pM->nChar ){
! 670: memcpy(pM->zText, pM->zBase, pM->nChar);
! 671: }
! 672: }else{
! 673: pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
! 674: }
! 675: }
! 676: }
! 677: if( pM->zText ){
! 678: if( nNewChar>0 ){
! 679: memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
! 680: pM->nChar += nNewChar;
! 681: }
! 682: pM->zText[pM->nChar] = 0;
! 683: }
! 684: }
! 685:
! 686: /*
! 687: ** This routine is a wrapper around xprintf() that invokes mout() as
! 688: ** the consumer.
! 689: */
! 690: static char *base_vprintf(
! 691: void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
! 692: int useInternal, /* Use internal %-conversions if true */
! 693: char *zInitBuf, /* Initially write here, before mallocing */
! 694: int nInitBuf, /* Size of zInitBuf[] */
! 695: const char *zFormat, /* format string */
! 696: va_list ap /* arguments */
! 697: ){
! 698: struct sgMprintf sM;
! 699: sM.zBase = sM.zText = zInitBuf;
! 700: sM.nChar = sM.nTotal = 0;
! 701: sM.nAlloc = nInitBuf;
! 702: sM.xRealloc = xRealloc;
! 703: vxprintf(mout, &sM, useInternal, zFormat, ap);
! 704: if( xRealloc ){
! 705: if( sM.zText==sM.zBase ){
! 706: sM.zText = xRealloc(0, sM.nChar+1);
! 707: memcpy(sM.zText, sM.zBase, sM.nChar+1);
! 708: }else if( sM.nAlloc>sM.nChar+10 ){
! 709: sM.zText = xRealloc(sM.zText, sM.nChar+1);
! 710: }
! 711: }
! 712: return sM.zText;
! 713: }
! 714:
! 715: /*
! 716: ** Realloc that is a real function, not a macro.
! 717: */
! 718: static void *printf_realloc(void *old, int size){
! 719: return sqliteRealloc(old,size);
! 720: }
! 721:
! 722: /*
! 723: ** Print into memory obtained from sqliteMalloc(). Use the internal
! 724: ** %-conversion extensions.
! 725: */
! 726: char *sqliteVMPrintf(const char *zFormat, va_list ap){
! 727: char zBase[1000];
! 728: return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
! 729: }
! 730:
! 731: /*
! 732: ** Print into memory obtained from sqliteMalloc(). Use the internal
! 733: ** %-conversion extensions.
! 734: */
! 735: char *sqliteMPrintf(const char *zFormat, ...){
! 736: va_list ap;
! 737: char *z;
! 738: char zBase[1000];
! 739: va_start(ap, zFormat);
! 740: z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
! 741: va_end(ap);
! 742: return z;
! 743: }
! 744:
! 745: /*
! 746: ** Print into memory obtained from malloc(). Do not use the internal
! 747: ** %-conversion extensions. This routine is for use by external users.
! 748: */
! 749: char *sqlite_mprintf(const char *zFormat, ...){
! 750: va_list ap;
! 751: char *z;
! 752: char zBuf[200];
! 753:
! 754: va_start(ap,zFormat);
! 755: z = base_vprintf((void*(*)(void*,int))realloc, 0,
! 756: zBuf, sizeof(zBuf), zFormat, ap);
! 757: va_end(ap);
! 758: return z;
! 759: }
! 760:
! 761: /* This is the varargs version of sqlite_mprintf.
! 762: */
! 763: char *sqlite_vmprintf(const char *zFormat, va_list ap){
! 764: char zBuf[200];
! 765: return base_vprintf((void*(*)(void*,int))realloc, 0,
! 766: zBuf, sizeof(zBuf), zFormat, ap);
! 767: }
! 768:
! 769: /*
! 770: ** sqlite_snprintf() works like snprintf() except that it ignores the
! 771: ** current locale settings. This is important for SQLite because we
! 772: ** are not able to use a "," as the decimal point in place of "." as
! 773: ** specified by some locales.
! 774: */
! 775: char *sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
! 776: char *z;
! 777: va_list ap;
! 778:
! 779: va_start(ap,zFormat);
! 780: z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
! 781: va_end(ap);
! 782: return z;
! 783: }
! 784:
! 785: /*
! 786: ** The following four routines implement the varargs versions of the
! 787: ** sqlite_exec() and sqlite_get_table() interfaces. See the sqlite.h
! 788: ** header files for a more detailed description of how these interfaces
! 789: ** work.
! 790: **
! 791: ** These routines are all just simple wrappers.
! 792: */
! 793: int sqlite_exec_printf(
! 794: sqlite *db, /* An open database */
! 795: const char *sqlFormat, /* printf-style format string for the SQL */
! 796: sqlite_callback xCallback, /* Callback function */
! 797: void *pArg, /* 1st argument to callback function */
! 798: char **errmsg, /* Error msg written here */
! 799: ... /* Arguments to the format string. */
! 800: ){
! 801: va_list ap;
! 802: int rc;
! 803:
! 804: va_start(ap, errmsg);
! 805: rc = sqlite_exec_vprintf(db, sqlFormat, xCallback, pArg, errmsg, ap);
! 806: va_end(ap);
! 807: return rc;
! 808: }
! 809: int sqlite_exec_vprintf(
! 810: sqlite *db, /* An open database */
! 811: const char *sqlFormat, /* printf-style format string for the SQL */
! 812: sqlite_callback xCallback, /* Callback function */
! 813: void *pArg, /* 1st argument to callback function */
! 814: char **errmsg, /* Error msg written here */
! 815: va_list ap /* Arguments to the format string. */
! 816: ){
! 817: char *zSql;
! 818: int rc;
! 819:
! 820: zSql = sqlite_vmprintf(sqlFormat, ap);
! 821: rc = sqlite_exec(db, zSql, xCallback, pArg, errmsg);
! 822: free(zSql);
! 823: return rc;
! 824: }
! 825: int sqlite_get_table_printf(
! 826: sqlite *db, /* An open database */
! 827: const char *sqlFormat, /* printf-style format string for the SQL */
! 828: char ***resultp, /* Result written to a char *[] that this points to */
! 829: int *nrow, /* Number of result rows written here */
! 830: int *ncol, /* Number of result columns written here */
! 831: char **errmsg, /* Error msg written here */
! 832: ... /* Arguments to the format string */
! 833: ){
! 834: va_list ap;
! 835: int rc;
! 836:
! 837: va_start(ap, errmsg);
! 838: rc = sqlite_get_table_vprintf(db, sqlFormat, resultp, nrow, ncol, errmsg, ap);
! 839: va_end(ap);
! 840: return rc;
! 841: }
! 842: int sqlite_get_table_vprintf(
! 843: sqlite *db, /* An open database */
! 844: const char *sqlFormat, /* printf-style format string for the SQL */
! 845: char ***resultp, /* Result written to a char *[] that this points to */
! 846: int *nrow, /* Number of result rows written here */
! 847: int *ncolumn, /* Number of result columns written here */
! 848: char **errmsg, /* Error msg written here */
! 849: va_list ap /* Arguments to the format string */
! 850: ){
! 851: char *zSql;
! 852: int rc;
! 853:
! 854: zSql = sqlite_vmprintf(sqlFormat, ap);
! 855: rc = sqlite_get_table(db, zSql, resultp, nrow, ncolumn, errmsg);
! 856: free(zSql);
! 857: return rc;
! 858: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>