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