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