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