RTS API Documentation  1.10.11
switch_mprintf.c
Go to the documentation of this file.
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 /*
54  * 20090210 (stkn):
55  * Taken from sqlite-3.3.x,
56  * renamed SQLITE_ -> SWITCH_,
57  * renamed visible functions to switch_*
58  * disabled functions without extra conversion specifiers
59  */
60 
61 #include <switch.h>
62 
63 #define LONGDOUBLE_TYPE long double
64 
65 /*
66 ** Conversion types fall into various categories as defined by the
67 ** following enumeration.
68 */
69 #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
70 #define etFLOAT 2 /* Floating point. %f */
71 #define etEXP 3 /* Exponentional notation. %e and %E */
72 #define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
73 #define etSIZE 5 /* Return number of characters processed so far. %n */
74 #define etSTRING 6 /* Strings. %s */
75 #define etDYNSTRING 7 /* Dynamically allocated strings. %z */
76 #define etPERCENT 8 /* Percent symbol. %% */
77 #define etCHARX 9 /* Characters. %c */
78 /* The rest are extensions, not normally found in printf() */
79 #define etCHARLIT 10 /* Literal characters. %' */
80 #define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */
81 #define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
82  NULL pointers replaced by SQL NULL. %Q */
83 #ifdef __UNSUPPORTED__
84 #define etTOKEN 13 /* a pointer to a Token structure */
85 #define etSRCLIST 14 /* a pointer to a SrcList */
86 #endif
87 #define etPOINTER 15 /* The %p conversion */
88 #define etSQLESCAPE3 16
89 #define etSQLESCAPE4 17
90 
91 /*
92 ** An "etByte" is an 8-bit unsigned value.
93 */
94 typedef unsigned char etByte;
95 
96 /*
97 ** Each builtin conversion character (ex: the 'd' in "%d") is described
98 ** by an instance of the following structure
99 */
100 typedef struct et_info { /* Information about each format field */
101  char fmttype; /* The format field code letter */
102  etByte base; /* The base for radix conversion */
103  etByte flags; /* One or more of FLAG_ constants below */
104  etByte type; /* Conversion paradigm */
105  etByte charset; /* Offset into aDigits[] of the digits string */
106  etByte prefix; /* Offset into aPrefix[] of the prefix string */
107 } et_info;
108 
109 /*
110 ** Allowed values for et_info.flags
111 */
112 #define FLAG_SIGNED 1 /* True if the value to convert is signed */
113 #define FLAG_INTERN 2 /* True if for internal use only */
114 #define FLAG_STRING 4 /* Allow infinity precision */
115 
116 
117 /*
118 ** The following table is searched linearly, so it is good to put the
119 ** most frequently used conversion types first.
120 */
121 static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
122 static const char aPrefix[] = "-x0\000X0";
123 static const et_info fmtinfo[] = {
124  {'d', 10, 1, etRADIX, 0, 0},
125  {'s', 0, 4, etSTRING, 0, 0},
126  {'g', 0, 1, etGENERIC, 30, 0},
127  {'z', 0, 6, etDYNSTRING, 0, 0},
128  {'q', 0, 4, etSQLESCAPE, 0, 0},
129  {'Q', 0, 4, etSQLESCAPE2, 0, 0},
130  {'w', 0, 4, etSQLESCAPE3, 0, 0},
131  {'y', 0, 4, etSQLESCAPE4, 0, 0},
132  {'c', 0, 0, etCHARX, 0, 0},
133  {'o', 8, 0, etRADIX, 0, 2},
134  {'u', 10, 0, etRADIX, 0, 0},
135  {'x', 16, 0, etRADIX, 16, 1},
136  {'X', 16, 0, etRADIX, 0, 4},
137 #ifndef SWITCH_OMIT_FLOATING_POINT
138  {'f', 0, 1, etFLOAT, 0, 0},
139  {'e', 0, 1, etEXP, 30, 0},
140  {'E', 0, 1, etEXP, 14, 0},
141  {'G', 0, 1, etGENERIC, 14, 0},
142 #endif
143  {'i', 10, 1, etRADIX, 0, 0},
144  {'n', 0, 0, etSIZE, 0, 0},
145  {'%', 0, 0, etPERCENT, 0, 0},
146  {'p', 16, 0, etPOINTER, 0, 1},
147 #ifdef __UNSUPPORTED__
148  {'T', 0, 2, etTOKEN, 0, 0},
149  {'S', 0, 2, etSRCLIST, 0, 0},
150 #endif
151 };
152 
153 #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
154 
155 /*
156 ** If SWITCH_OMIT_FLOATING_POINT is defined, then none of the floating point
157 ** conversions will work.
158 */
159 #ifndef SWITCH_OMIT_FLOATING_POINT
160 /*
161 ** "*val" is a double such that 0.1 <= *val < 10.0
162 ** Return the ascii code for the leading digit of *val, then
163 ** multiply "*val" by 10.0 to renormalize.
164 **
165 ** Example:
166 ** input: *val = 3.14159
167 ** output: *val = 1.4159 function return = '3'
168 **
169 ** The counter *cnt is incremented each time. After counter exceeds
170 ** 16 (the number of significant digits in a 64-bit float) '0' is
171 ** always returned.
172 */
173 static int et_getdigit(LONGDOUBLE_TYPE * val, int *cnt)
174 {
175  int digit;
176  LONGDOUBLE_TYPE d;
177  if ((*cnt)++ >= 16)
178  return '0';
179  digit = (int) *val;
180  d = digit;
181  digit += '0';
182  *val = (*val - d) * 10.0;
183  return digit;
184 }
185 #endif /* SWITCH_OMIT_FLOATING_POINT */
186 
187 /*
188 ** On machines with a small stack size, you can redefine the
189 ** SWITCH_PRINT_BUF_SIZE to be less than 350. But beware - for
190 ** smaller values some %f conversions may go into an infinite loop.
191 */
192 #ifndef SWITCH_PRINT_BUF_SIZE
193 # define SWITCH_PRINT_BUF_SIZE 350
194 #endif
195 #define etBUFSIZE SWITCH_PRINT_BUF_SIZE /* Size of the output buffer */
196 
197 /*
198 ** The root program. All variations call this core.
199 **
200 ** INPUTS:
201 ** func This is a pointer to a function taking three arguments
202 ** 1. A pointer to anything. Same as the "arg" parameter.
203 ** 2. A pointer to the list of characters to be output
204 ** (Note, this list is NOT null terminated.)
205 ** 3. An integer number of characters to be output.
206 ** (Note: This number might be zero.)
207 **
208 ** arg This is the pointer to anything which will be passed as the
209 ** first argument to "func". Use it for whatever you like.
210 **
211 ** fmt This is the format string, as in the usual print.
212 **
213 ** ap This is a pointer to a list of arguments. Same as in
214 ** vfprint.
215 **
216 ** OUTPUTS:
217 ** The return value is the total number of characters sent to
218 ** the function "func". Returns -1 on a error.
219 **
220 ** Note that the order in which automatic variables are declared below
221 ** seems to make a big difference in determining how fast this beast
222 ** will run.
223 */
224 static int vxprintf(void (*func) (void *, const char *, int), /* Consumer of text */
225  void *arg, /* First argument to the consumer */
226  int useExtended, /* Allow extended %-conversions */
227  const char *fmt, /* Format string */
228  va_list ap /* arguments */
229  )
230 {
231  int c; /* Next character in the format string */
232  char *bufpt; /* Pointer to the conversion buffer */
233  int precision; /* Precision of the current field */
234  int length; /* Length of the field */
235  int idx; /* A general purpose loop counter */
236  int count; /* Total number of characters output */
237  int width; /* Width of the current field */
238  etByte flag_leftjustify; /* True if "-" flag is present */
239  etByte flag_plussign; /* True if "+" flag is present */
240  etByte flag_blanksign; /* True if " " flag is present */
241  etByte flag_alternateform; /* True if "#" flag is present */
242  etByte flag_altform2; /* True if "!" flag is present */
243  etByte flag_zeropad; /* True if field width constant starts with zero */
244  etByte flag_long; /* True if "l" flag is present */
245  etByte flag_longlong; /* True if the "ll" flag is present */
246  etByte done; /* Loop termination flag */
247  uint64_t longvalue; /* Value for integer types */
248  LONGDOUBLE_TYPE realvalue; /* Value for real types */
249  const et_info *infop; /* Pointer to the appropriate info structure */
250  char buf[etBUFSIZE]; /* Conversion buffer */
251  char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
252  etByte errorflag = 0; /* True if an error is encountered */
253  etByte xtype = 0; /* Conversion paradigm */
254  char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
255  static const char spaces[] = " ";
256 #define etSPACESIZE (sizeof(spaces)-1)
257 #ifndef SWITCH_OMIT_FLOATING_POINT
258  int exp, e2; /* exponent of real numbers */
259  double rounder; /* Used for rounding floating point values */
260  etByte flag_dp; /* True if decimal point should be shown */
261  etByte flag_rtz; /* True if trailing zeros should be removed */
262  etByte flag_exp; /* True to force display of the exponent */
263  int nsd; /* Number of significant digits returned */
264 #endif
265 
266  func(arg, "", 0);
267  count = length = 0;
268  bufpt = 0;
269  for (; (c = (*fmt)) != 0; ++fmt) {
270  if (c != '%') {
271  int amt;
272  bufpt = (char *) fmt;
273  amt = 1;
274  while ((c = (*++fmt)) != '%' && c != 0)
275  amt++;
276  (*func) (arg, bufpt, amt);
277  count += amt;
278  if (c == 0)
279  break;
280  }
281  if ((c = (*++fmt)) == 0) {
282  errorflag = 1;
283  (*func) (arg, "%", 1);
284  count++;
285  break;
286  }
287  /* Find out what flags are present */
288  flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_altform2 = flag_zeropad = 0;
289  done = 0;
290  do {
291  switch (c) {
292  case '-':
293  flag_leftjustify = 1;
294  break;
295  case '+':
296  flag_plussign = 1;
297  break;
298  case ' ':
299  flag_blanksign = 1;
300  break;
301  case '#':
302  flag_alternateform = 1;
303  break;
304  case '!':
305  flag_altform2 = 1;
306  break;
307  case '0':
308  flag_zeropad = 1;
309  break;
310  default:
311  done = 1;
312  break;
313  }
314  } while (!done && (c = (*++fmt)) != 0);
315  /* Get the field width */
316  width = 0;
317  if (c == '*') {
318  width = va_arg(ap, int);
319  if (width < 0) {
320  flag_leftjustify = 1;
321  width = -width;
322  }
323  c = *++fmt;
324  } else {
325  while (c >= '0' && c <= '9') {
326  width = width * 10 + c - '0';
327  c = *++fmt;
328  }
329  }
330  if (width > etBUFSIZE - 10) {
331  width = etBUFSIZE - 10;
332  }
333  /* Get the precision */
334  if (c == '.') {
335  precision = 0;
336  c = *++fmt;
337  if (c == '*') {
338  precision = va_arg(ap, int);
339  if (precision < 0)
340  precision = -precision;
341  c = *++fmt;
342  } else {
343  while (c >= '0' && c <= '9') {
344  precision = precision * 10 + c - '0';
345  c = *++fmt;
346  }
347  }
348  } else {
349  precision = -1;
350  }
351  /* Get the conversion type modifier */
352  if (c == 'l') {
353  flag_long = 1;
354  c = *++fmt;
355  if (c == 'l') {
356  flag_longlong = 1;
357  c = *++fmt;
358  } else {
359  flag_longlong = 0;
360  }
361  } else {
362  flag_long = flag_longlong = 0;
363  }
364  /* Fetch the info entry for the field */
365  infop = 0;
366  for (idx = 0; idx < etNINFO; idx++) {
367  if (c == fmtinfo[idx].fmttype) {
368  infop = &fmtinfo[idx];
369  if (useExtended || (infop->flags & FLAG_INTERN) == 0) {
370  xtype = infop->type;
371  } else {
372  return -1;
373  }
374  break;
375  }
376  }
377  zExtra = 0;
378  if (infop == 0) {
379  return -1;
380  }
381 
382 
383  /* Limit the precision to prevent overflowing buf[] during conversion */
384  if (precision > etBUFSIZE - 40 && (infop->flags & FLAG_STRING) == 0) {
385  precision = etBUFSIZE - 40;
386  }
387 
388  /*
389  ** At this point, variables are initialized as follows:
390  **
391  ** flag_alternateform TRUE if a '#' is present.
392  ** flag_altform2 TRUE if a '!' is present.
393  ** flag_plussign TRUE if a '+' is present.
394  ** flag_leftjustify TRUE if a '-' is present or if the
395  ** field width was negative.
396  ** flag_zeropad TRUE if the width began with 0.
397  ** flag_long TRUE if the letter 'l' (ell) prefixed
398  ** the conversion character.
399  ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
400  ** the conversion character.
401  ** flag_blanksign TRUE if a ' ' is present.
402  ** width The specified field width. This is
403  ** always non-negative. Zero is the default.
404  ** precision The specified precision. The default
405  ** is -1.
406  ** xtype The class of the conversion.
407  ** infop Pointer to the appropriate info struct.
408  */
409  switch (xtype) {
410  case etPOINTER:
411  flag_longlong = sizeof(char *) == sizeof(int64_t);
412  flag_long = sizeof(char *) == sizeof(long int);
413  /* Fall through into the next case */
414  case etRADIX:
415  if (infop->flags & FLAG_SIGNED) {
416  int64_t v;
417  if (flag_longlong)
418  v = va_arg(ap, int64_t);
419  else if (flag_long)
420  v = va_arg(ap, long int);
421  else
422  v = va_arg(ap, int);
423  if (v < 0) {
424  longvalue = -v;
425  prefix = '-';
426  } else {
427  longvalue = v;
428  if (flag_plussign)
429  prefix = '+';
430  else if (flag_blanksign)
431  prefix = ' ';
432  else
433  prefix = 0;
434  }
435  } else {
436  if (flag_longlong)
437  longvalue = va_arg(ap, uint64_t);
438  else if (flag_long)
439  longvalue = va_arg(ap, unsigned long int);
440  else
441  longvalue = va_arg(ap, unsigned int);
442  prefix = 0;
443  }
444  if (longvalue == 0)
445  flag_alternateform = 0;
446  if (flag_zeropad && precision < width - (prefix != 0)) {
447  precision = width - (prefix != 0);
448  }
449  bufpt = &buf[etBUFSIZE - 1];
450  {
451  register const char *cset; /* Use registers for speed */
452  register int base;
453  cset = &aDigits[infop->charset];
454  base = infop->base;
455  do { /* Convert to ascii */
456  *(--bufpt) = cset[longvalue % base];
457  longvalue = longvalue / base;
458  } while (longvalue > 0);
459  }
460  length = (int)(&buf[etBUFSIZE - 1] - bufpt);
461  for (idx = precision - length; idx > 0; idx--) {
462  *(--bufpt) = '0'; /* Zero pad */
463  }
464  if (prefix)
465  *(--bufpt) = prefix; /* Add sign */
466  if (flag_alternateform && infop->prefix) { /* Add "0" or "0x" */
467  const char *pre;
468  char x;
469  pre = &aPrefix[infop->prefix];
470  if (*bufpt != pre[0]) {
471  for (; (x = (*pre)) != 0; pre++)
472  *(--bufpt) = x;
473  }
474  }
475  length = (int)(&buf[etBUFSIZE - 1] - bufpt);
476  break;
477  case etFLOAT:
478  case etEXP:
479  case etGENERIC:
480  realvalue = va_arg(ap, double);
481 #ifndef SWITCH_OMIT_FLOATING_POINT
482  if (precision < 0)
483  precision = 6; /* Set default precision */
484  if (precision > etBUFSIZE / 2 - 10)
485  precision = etBUFSIZE / 2 - 10;
486  if (realvalue < 0.0) {
487  realvalue = -realvalue;
488  prefix = '-';
489  } else {
490  if (flag_plussign)
491  prefix = '+';
492  else if (flag_blanksign)
493  prefix = ' ';
494  else
495  prefix = 0;
496  }
497  if (xtype == etGENERIC && precision > 0)
498  precision--;
499 #if 0
500  /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
501  for (idx = precision, rounder = 0.4999; idx > 0; idx--, rounder *= 0.1);
502 #else
503  /* It makes more sense to use 0.5 */
504  for (idx = precision, rounder = 0.5; idx > 0; idx--, rounder *= 0.1) {
505  }
506 #endif
507  if (xtype == etFLOAT)
508  realvalue += rounder;
509  /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
510  exp = 0;
511  if (realvalue > 0.0) {
512  while (realvalue >= 1e32 && exp <= 350) {
513  realvalue *= 1e-32;
514  exp += 32;
515  }
516  while (realvalue >= 1e8 && exp <= 350) {
517  realvalue *= 1e-8;
518  exp += 8;
519  }
520  while (realvalue >= 10.0 && exp <= 350) {
521  realvalue *= 0.1;
522  exp++;
523  }
524  while (realvalue < 1e-8 && exp >= -350) {
525  realvalue *= 1e8;
526  exp -= 8;
527  }
528  while (realvalue < 1.0 && exp >= -350) {
529  realvalue *= 10.0;
530  exp--;
531  }
532  if (exp > 350 || exp < -350) {
533  bufpt = "NaN";
534  length = 3;
535  break;
536  }
537  }
538  bufpt = buf;
539  /*
540  ** If the field type is etGENERIC, then convert to either etEXP
541  ** or etFLOAT, as appropriate.
542  */
543  flag_exp = xtype == etEXP;
544  if (xtype != etFLOAT) {
545  realvalue += rounder;
546  if (realvalue >= 10.0) {
547  realvalue *= 0.1;
548  exp++;
549  }
550  }
551  if (xtype == etGENERIC) {
552  flag_rtz = !flag_alternateform;
553  if (exp < -4 || exp > precision) {
554  xtype = etEXP;
555  } else {
556  precision = precision - exp;
557  xtype = etFLOAT;
558  }
559  } else {
560  flag_rtz = 0;
561  }
562  if (xtype == etEXP) {
563  e2 = 0;
564  } else {
565  e2 = exp;
566  }
567  nsd = 0;
568  flag_dp = (precision > 0) | flag_alternateform | flag_altform2;
569  /* The sign in front of the number */
570  if (prefix) {
571  *(bufpt++) = prefix;
572  }
573  /* Digits prior to the decimal point */
574  if (e2 < 0) {
575  *(bufpt++) = '0';
576  } else {
577  for (; e2 >= 0; e2--) {
578  *(bufpt++) = (char) et_getdigit(&realvalue, &nsd);
579  }
580  }
581  /* The decimal point */
582  if (flag_dp) {
583  *(bufpt++) = '.';
584  }
585  /* "0" digits after the decimal point but before the first
586  ** significant digit of the number */
587  for (e2++; e2 < 0 && precision > 0; precision--, e2++) {
588  *(bufpt++) = '0';
589  }
590  /* Significant digits after the decimal point */
591  while ((precision--) > 0) {
592  *(bufpt++) = (char) et_getdigit(&realvalue, &nsd);
593  }
594  /* Remove trailing zeros and the "." if no digits follow the "." */
595  if (flag_rtz && flag_dp) {
596  while (bufpt[-1] == '0')
597  *(--bufpt) = 0;
598  assert(bufpt > buf);
599  if (bufpt[-1] == '.') {
600  if (flag_altform2) {
601  *(bufpt++) = '0';
602  } else {
603  *(--bufpt) = 0;
604  }
605  }
606  }
607  /* Add the "eNNN" suffix */
608  if (flag_exp || (xtype == etEXP && exp)) {
609  *(bufpt++) = aDigits[infop->charset];
610  if (exp < 0) {
611  *(bufpt++) = '-';
612  exp = -exp;
613  } else {
614  *(bufpt++) = '+';
615  }
616  if (exp >= 100) {
617  *(bufpt++) = (char) (exp / 100) + '0'; /* 100's digit */
618  exp %= 100;
619  }
620  *(bufpt++) = (char) exp / 10 + '0'; /* 10's digit */
621  *(bufpt++) = exp % 10 + '0'; /* 1's digit */
622  }
623  *bufpt = 0;
624 
625  /* The converted number is in buf[] and zero terminated. Output it.
626  ** Note that the number is in the usual order, not reversed as with
627  ** integer conversions. */
628  length = (int)(bufpt - buf);
629  bufpt = buf;
630 
631  /* Special case: Add leading zeros if the flag_zeropad flag is
632  ** set and we are not left justified */
633  if (flag_zeropad && !flag_leftjustify && length < width) {
634  int i;
635  int nPad = width - length;
636  for (i = width; i >= nPad; i--) {
637  bufpt[i] = bufpt[i - nPad];
638  }
639  i = prefix != 0;
640  while (nPad--)
641  bufpt[i++] = '0';
642  length = width;
643  }
644 #endif
645  break;
646  case etSIZE:
647  *(va_arg(ap, int *)) = count;
648  length = width = 0;
649  break;
650  case etPERCENT:
651  buf[0] = '%';
652  bufpt = buf;
653  length = 1;
654  break;
655  case etCHARLIT:
656  case etCHARX:
657  c = buf[0] = (char) (xtype == etCHARX ? va_arg(ap, int) : *++fmt);
658  if (precision >= 0) {
659  for (idx = 1; idx < precision; idx++)
660  buf[idx] = (char) c;
661  length = precision;
662  } else {
663  length = 1;
664  }
665  bufpt = buf;
666  break;
667  case etSTRING:
668  case etDYNSTRING:
669  bufpt = va_arg(ap, char *);
670  if (bufpt == 0) {
671  bufpt = "";
672  } else if (xtype == etDYNSTRING) {
673  zExtra = bufpt;
674  }
675  length = (int)strlen(bufpt);
676  if (precision >= 0 && precision < length)
677  length = precision;
678  break;
679  case etSQLESCAPE:
680  case etSQLESCAPE2:
681  case etSQLESCAPE4:
682  case etSQLESCAPE3:{
683  size_t i, j, n, ch;
684  int needQuote, isnull;
685  char *escarg = va_arg(ap, char *);
686  isnull = escarg == 0;
687  if (isnull)
688  escarg = (xtype == etSQLESCAPE2 ? "NULL" : "(NULL)");
689  for (i = n = 0; (ch = escarg[i]) != 0; i++) {
690  if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\'))
691  n++;
692  }
693  needQuote = !isnull && xtype == etSQLESCAPE2;
694  n += i + 1 + needQuote * 2;
695  if (n > etBUFSIZE) {
696  bufpt = zExtra = malloc(n);
697  if (bufpt == 0)
698  return -1;
699  } else {
700  bufpt = buf;
701  }
702  j = 0;
703  if (needQuote)
704  bufpt[j++] = '\'';
705  for (i = 0; (ch = escarg[i]) != 0; i++) {
706  bufpt[j++] = (char) ch;
707  if (xtype == etSQLESCAPE4) {
708  if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\')) {
709  bufpt[j] = (char) ch;
710  bufpt[j-1] = (char) '\\';
711  j++;
712  }
713  } else {
714  if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\'))
715  bufpt[j++] = (char) ch;
716  }
717  }
718  if (needQuote)
719  bufpt[j++] = '\'';
720  bufpt[j] = 0;
721  length = j;
722  /* The precision is ignored on %q and %Q */
723  /* if ( precision>=0 && precision<length ) length = precision; */
724  break;
725  }
726 #ifdef __UNSUPPORTED__
727  case etTOKEN:{
728  Token *pToken = va_arg(ap, Token *);
729  if (pToken && pToken->z) {
730  (*func) (arg, (char *) pToken->z, pToken->n);
731  }
732  length = width = 0;
733  break;
734  }
735  case etSRCLIST:{
736  SrcList *pSrc = va_arg(ap, SrcList *);
737  int k = va_arg(ap, int);
738  struct SrcList_item *pItem = &pSrc->a[k];
739  assert(k >= 0 && k < pSrc->nSrc);
740  if (pItem->zDatabase && pItem->zDatabase[0]) {
741  (*func) (arg, pItem->zDatabase, strlen(pItem->zDatabase));
742  (*func) (arg, ".", 1);
743  }
744  (*func) (arg, pItem->zName, strlen(pItem->zName));
745  length = width = 0;
746  break;
747  }
748 #endif
749  } /* End switch over the format type */
750  /*
751  ** The text of the conversion is pointed to by "bufpt" and is
752  ** "length" characters long. The field width is "width". Do
753  ** the output.
754  */
755  if (!flag_leftjustify) {
756  register int nspace;
757  nspace = width - length;
758  if (nspace > 0) {
759  count += nspace;
760  while (nspace >= etSPACESIZE) {
761  (*func) (arg, spaces, etSPACESIZE);
762  nspace -= etSPACESIZE;
763  }
764  if (nspace > 0)
765  (*func) (arg, spaces, nspace);
766  }
767  }
768  if (length > 0) {
769  (*func) (arg, bufpt, length);
770  count += length;
771  }
772  if (flag_leftjustify) {
773  register int nspace;
774  nspace = width - length;
775  if (nspace > 0) {
776  count += nspace;
777  while (nspace >= etSPACESIZE) {
778  (*func) (arg, spaces, etSPACESIZE);
779  nspace -= etSPACESIZE;
780  }
781  if (nspace > 0)
782  (*func) (arg, spaces, nspace);
783  }
784  }
785  if (zExtra) {
786  free(zExtra);
787  }
788  } /* End for loop over the format string */
789  return errorflag ? -1 : count;
790 } /* End of function */
791 
792 
793 /* This structure is used to store state information about the
794 ** write to memory that is currently in progress.
795 */
796 struct sgMprintf {
797  char *zBase; /* A base allocation */
798  char *zText; /* The string collected so far */
799  int nChar; /* Length of the string so far */
800  int nTotal; /* Output size if unconstrained */
801  int nAlloc; /* Amount of space allocated in zText */
802  void *(*xRealloc) (void *, int); /* Function used to realloc memory */
803 };
804 
805 /*
806 ** This function implements the callback from vxprintf.
807 **
808 ** This routine add nNewChar characters of text in zNewText to
809 ** the sgMprintf structure pointed to by "arg".
810 */
811 static void mout(void *arg, const char *zNewText, int nNewChar)
812 {
813  struct sgMprintf *pM = (struct sgMprintf *) arg;
814  pM->nTotal += nNewChar;
815  if (pM->nChar + nNewChar + 1 > pM->nAlloc) {
816  if (pM->xRealloc == 0) {
817  nNewChar = pM->nAlloc - pM->nChar - 1;
818  } else {
819  pM->nAlloc = pM->nChar + nNewChar * 2 + 1;
820  if (pM->zText == pM->zBase) {
821  pM->zText = pM->xRealloc(0, pM->nAlloc);
822  if (pM->zText && pM->nChar) {
823  memcpy(pM->zText, pM->zBase, pM->nChar);
824  }
825  } else {
826  char *zNew;
827  zNew = pM->xRealloc(pM->zText, pM->nAlloc);
828  if (zNew) {
829  pM->zText = zNew;
830  }
831  }
832  }
833  }
834  if (pM->zText) {
835  if (nNewChar > 0) {
836  memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
837  pM->nChar += nNewChar;
838  }
839  pM->zText[pM->nChar] = 0;
840  }
841 }
842 
843 /*
844 ** This routine is a wrapper around xprintf() that invokes mout() as
845 ** the consumer.
846 */
847 static char *base_vprintf(void *(*xRealloc) (void *, int), /* Routine to realloc memory. May be NULL */
848  int useInternal, /* Use internal %-conversions if true */
849  char *zInitBuf, /* Initially write here, before mallocing */
850  int nInitBuf, /* Size of zInitBuf[] */
851  const char *zFormat, /* format string */
852  va_list ap /* arguments */
853  )
854 {
855  struct sgMprintf sM;
856  sM.zBase = sM.zText = zInitBuf;
857  sM.nChar = sM.nTotal = 0;
858  sM.nAlloc = nInitBuf;
859  sM.xRealloc = xRealloc;
860  vxprintf(mout, &sM, useInternal, zFormat, ap);
861  if (xRealloc) {
862  if (sM.zText == sM.zBase) {
863  sM.zText = xRealloc(0, sM.nChar + 1);
864  if (sM.zText) {
865  memcpy(sM.zText, sM.zBase, sM.nChar + 1);
866  }
867  } else if (sM.nAlloc > sM.nChar + 10) {
868  char *zNew = xRealloc(sM.zText, sM.nChar + 1);
869  if (zNew) {
870  sM.zText = zNew;
871  }
872  }
873  }
874  return sM.zText;
875 }
876 
877 /*
878 ** Realloc that is a real function, not a macro.
879 */
880 static void *printf_realloc(void *old, int size)
881 {
882  return realloc(old, size);
883 }
884 
885 /*
886 ** Print into memory. Omit the internal %-conversion extensions.
887 */
888 SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap)
889 {
891  return base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
892 }
893 
894 /*
895 ** Print into memory. Omit the internal %-conversion extensions.
896 */
897 SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...)
898 {
899  va_list ap;
900  char *z;
902  va_start(ap, zFormat);
903  z = base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
904  va_end(ap);
905  return z;
906 }
907 
908 /*
909 ** sqlite3_snprintf() works like snprintf() except that it ignores the
910 ** current locale settings. This is important for SQLite because we
911 ** are not able to use a "," as the decimal point in place of "." as
912 ** specified by some locales.
913 */
914 SWITCH_DECLARE(char *) switch_snprintfv(char *zBuf, int n, const char *zFormat, ...)
915 {
916  char *z;
917  va_list ap;
918 
919  va_start(ap, zFormat);
920  z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
921  va_end(ap);
922  return z;
923 }
924 
925 /* For Emacs:
926  * Local Variables:
927  * mode:c
928  * indent-tabs-mode:t
929  * tab-width:4
930  * c-basic-offset:4
931  * End:
932  * For VIM:
933  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
934  */
char * switch_mprintf(const char *zFormat,...)
#define SWITCH_PRINT_BUF_SIZE
etByte charset
static char * base_vprintf(void *(*xRealloc)(void *, int), int useInternal, char *zInitBuf, int nInitBuf, const char *zFormat, va_list ap)
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt)
#define etSQLESCAPE4
char * zBase
static const et_info fmtinfo[]
static void * printf_realloc(void *old, int size)
char * zText
#define etBUFSIZE
#define etRADIX
#define etEXP
etByte type
static const char aPrefix[]
#define etSTRING
#define FLAG_STRING
unsigned char etByte
int cJSON_bool fmt
Definition: switch_cJSON.h:150
etByte prefix
#define etSIZE
static const char aDigits[]
switch_byte_t switch_byte_t * buf
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
void *(* xRealloc)(void *, int)
#define etSPACESIZE
char fmttype
#define etNINFO
etByte flags
char const int length
Definition: switch_cJSON.h:153
#define etCHARLIT
static void mout(void *arg, const char *zNewText, int nNewChar)
static int vxprintf(void(*func)(void *, const char *, int), void *arg, int useExtended, const char *fmt, va_list ap)
#define LONGDOUBLE_TYPE
char * switch_snprintfv(char *zBuf, int n, const char *zFormat,...)
#define FLAG_INTERN
Main Library Header.
#define SWITCH_DECLARE(type)
#define etSQLESCAPE
#define etFLOAT
#define etPERCENT
#define etGENERIC
#define etPOINTER
char * switch_vmprintf(const char *zFormat, va_list ap)
struct et_info et_info
#define etCHARX
int count
Definition: switch_cJSON.h:204
#define etSQLESCAPE3
etByte base
#define etDYNSTRING
#define etSQLESCAPE2
#define FLAG_SIGNED