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