PostgreSQL Source Code  git master
snprintf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1983, 1995, 1996 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  * The Regents of the University of California. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * src/port/snprintf.c
31  */
32 
33 #include "c.h"
34 
35 #include <ctype.h>
36 #ifdef _MSC_VER
37 #include <float.h> /* for _isnan */
38 #endif
39 #include <limits.h>
40 #include <math.h>
41 #ifndef WIN32
42 #include <sys/ioctl.h>
43 #endif
44 #include <sys/param.h>
45 
46 #ifndef NL_ARGMAX
47 #define NL_ARGMAX 16
48 #endif
49 
50 
51 /*
52  * SNPRINTF, VSNPRINTF and friends
53  *
54  * These versions have been grabbed off the net. They have been
55  * cleaned up to compile properly and support for most of the Single Unix
56  * Specification has been added. Remaining unimplemented features are:
57  *
58  * 1. No locale support: the radix character is always '.' and the '
59  * (single quote) format flag is ignored.
60  *
61  * 2. No support for the "%n" format specification.
62  *
63  * 3. No support for wide characters ("lc" and "ls" formats).
64  *
65  * 4. No support for "long double" ("Lf" and related formats).
66  *
67  * 5. Space and '#' flags are not implemented.
68  *
69  *
70  * The result values of these functions are not the same across different
71  * platforms. This implementation is compatible with the Single Unix Spec:
72  *
73  * 1. -1 is returned only if processing is abandoned due to an invalid
74  * parameter, such as incorrect format string. (Although not required by
75  * the spec, this happens only when no characters have yet been transmitted
76  * to the destination.)
77  *
78  * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0;
79  * no data has been stored.
80  *
81  * 3. Otherwise, the number of bytes actually transmitted to the destination
82  * is returned (excluding the trailing '\0' for snprintf and sprintf).
83  *
84  * For snprintf with nonzero count, the result cannot be more than count-1
85  * (a trailing '\0' is always stored); it is not possible to distinguish
86  * buffer overrun from exact fit. This is unlike some implementations that
87  * return the number of bytes that would have been needed for the complete
88  * result string.
89  */
90 
91 /**************************************************************
92  * Original:
93  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
94  * A bombproof version of doprnt (dopr) included.
95  * Sigh. This sort of thing is always nasty do deal with. Note that
96  * the version here does not include floating point. (now it does ... tgl)
97  **************************************************************/
98 
99 /* Prevent recursion */
100 #undef vsnprintf
101 #undef snprintf
102 #undef sprintf
103 #undef vfprintf
104 #undef fprintf
105 #undef printf
106 
107 /* Info about where the formatted output is going */
108 typedef struct
109 {
110  char *bufptr; /* next buffer output position */
111  char *bufstart; /* first buffer element */
112  char *bufend; /* last buffer element, or NULL */
113  /* bufend == NULL is for sprintf, where we assume buf is big enough */
114  FILE *stream; /* eventual output destination, or NULL */
115  int nchars; /* # chars already sent to stream */
116  bool failed; /* call is a failure; errno is set */
117 } PrintfTarget;
118 
119 /*
120  * Info about the type and value of a formatting parameter. Note that we
121  * don't currently support "long double", "wint_t", or "wchar_t *" data,
122  * nor the '%n' formatting code; else we'd need more types. Also, at this
123  * level we need not worry about signed vs unsigned values.
124  */
125 typedef enum
126 {
133 } PrintfArgType;
134 
135 typedef union
136 {
137  int i;
138  long l;
139  int64 ll;
140  double d;
141  char *cptr;
143 
144 
145 static void flushbuffer(PrintfTarget *target);
146 static void dopr(PrintfTarget *target, const char *format, va_list args);
147 
148 
149 int
150 pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
151 {
152  PrintfTarget target;
153 
154  if (str == NULL || count == 0)
155  return 0;
156  target.bufstart = target.bufptr = str;
157  target.bufend = str + count - 1;
158  target.stream = NULL;
159  /* target.nchars is unused in this case */
160  target.failed = false;
161  dopr(&target, fmt, args);
162  *(target.bufptr) = '\0';
163  return target.failed ? -1 : (target.bufptr - target.bufstart);
164 }
165 
166 int
167 pg_snprintf(char *str, size_t count, const char *fmt,...)
168 {
169  int len;
170  va_list args;
171 
172  va_start(args, fmt);
173  len = pg_vsnprintf(str, count, fmt, args);
174  va_end(args);
175  return len;
176 }
177 
178 static int
179 pg_vsprintf(char *str, const char *fmt, va_list args)
180 {
181  PrintfTarget target;
182 
183  if (str == NULL)
184  return 0;
185  target.bufstart = target.bufptr = str;
186  target.bufend = NULL;
187  target.stream = NULL;
188  /* target.nchars is unused in this case */
189  target.failed = false;
190  dopr(&target, fmt, args);
191  *(target.bufptr) = '\0';
192  return target.failed ? -1 : (target.bufptr - target.bufstart);
193 }
194 
195 int
196 pg_sprintf(char *str, const char *fmt,...)
197 {
198  int len;
199  va_list args;
200 
201  va_start(args, fmt);
202  len = pg_vsprintf(str, fmt, args);
203  va_end(args);
204  return len;
205 }
206 
207 int
208 pg_vfprintf(FILE *stream, const char *fmt, va_list args)
209 {
210  PrintfTarget target;
211  char buffer[1024]; /* size is arbitrary */
212 
213  if (stream == NULL)
214  {
215  errno = EINVAL;
216  return -1;
217  }
218  target.bufstart = target.bufptr = buffer;
219  target.bufend = buffer + sizeof(buffer) - 1;
220  target.stream = stream;
221  target.nchars = 0;
222  target.failed = false;
223  dopr(&target, fmt, args);
224  /* dump any remaining buffer contents */
225  flushbuffer(&target);
226  return target.failed ? -1 : target.nchars;
227 }
228 
229 int
230 pg_fprintf(FILE *stream, const char *fmt,...)
231 {
232  int len;
233  va_list args;
234 
235  va_start(args, fmt);
236  len = pg_vfprintf(stream, fmt, args);
237  va_end(args);
238  return len;
239 }
240 
241 int
242 pg_printf(const char *fmt,...)
243 {
244  int len;
245  va_list args;
246 
247  va_start(args, fmt);
248  len = pg_vfprintf(stdout, fmt, args);
249  va_end(args);
250  return len;
251 }
252 
253 /*
254  * Attempt to write the entire buffer to target->stream; discard the entire
255  * buffer in any case. Call this only when target->stream is defined.
256  */
257 static void
259 {
260  size_t nc = target->bufptr - target->bufstart;
261 
262  if (!target->failed && nc > 0)
263  {
264  size_t written;
265 
266  written = fwrite(target->bufstart, 1, nc, target->stream);
267  target->nchars += written;
268  if (written != nc)
269  target->failed = true;
270  }
271  target->bufptr = target->bufstart;
272 }
273 
274 
275 static void fmtstr(char *value, int leftjust, int minlen, int maxwidth,
276  int pointflag, PrintfTarget *target);
277 static void fmtptr(void *value, PrintfTarget *target);
278 static void fmtint(int64 value, char type, int forcesign,
279  int leftjust, int minlen, int zpad, int precision, int pointflag,
280  PrintfTarget *target);
281 static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target);
282 static void fmtfloat(double value, char type, int forcesign,
283  int leftjust, int minlen, int zpad, int precision, int pointflag,
284  PrintfTarget *target);
285 static void dostr(const char *str, int slen, PrintfTarget *target);
286 static void dopr_outch(int c, PrintfTarget *target);
287 static int adjust_sign(int is_negative, int forcesign, int *signvalue);
288 static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen);
289 static void leading_pad(int zpad, int *signvalue, int *padlen,
290  PrintfTarget *target);
291 static void trailing_pad(int *padlen, PrintfTarget *target);
292 
293 
294 /*
295  * dopr(): poor man's version of doprintf
296  */
297 static void
298 dopr(PrintfTarget *target, const char *format, va_list args)
299 {
300  const char *format_start = format;
301  int ch;
302  bool have_dollar;
303  bool have_non_dollar;
304  bool have_star;
305  bool afterstar;
306  int accum;
307  int longlongflag;
308  int longflag;
309  int pointflag;
310  int leftjust;
311  int fieldwidth;
312  int precision;
313  int zpad;
314  int forcesign;
315  int last_dollar;
316  int fmtpos;
317  int cvalue;
318  int64 numvalue;
319  double fvalue;
320  char *strvalue;
321  int i;
322  PrintfArgType argtypes[NL_ARGMAX + 1];
323  PrintfArgValue argvalues[NL_ARGMAX + 1];
324 
325  /*
326  * Parse the format string to determine whether there are %n$ format
327  * specs, and identify the types and order of the format parameters.
328  */
329  have_dollar = have_non_dollar = false;
330  last_dollar = 0;
331  MemSet(argtypes, 0, sizeof(argtypes));
332 
333  while ((ch = *format++) != '\0')
334  {
335  if (ch != '%')
336  continue;
337  longflag = longlongflag = pointflag = 0;
338  fmtpos = accum = 0;
339  afterstar = false;
340 nextch1:
341  ch = *format++;
342  if (ch == '\0')
343  break; /* illegal, but we don't complain */
344  switch (ch)
345  {
346  case '-':
347  case '+':
348  goto nextch1;
349  case '0':
350  case '1':
351  case '2':
352  case '3':
353  case '4':
354  case '5':
355  case '6':
356  case '7':
357  case '8':
358  case '9':
359  accum = accum * 10 + (ch - '0');
360  goto nextch1;
361  case '.':
362  pointflag = 1;
363  accum = 0;
364  goto nextch1;
365  case '*':
366  if (afterstar)
367  have_non_dollar = true; /* multiple stars */
368  afterstar = true;
369  accum = 0;
370  goto nextch1;
371  case '$':
372  have_dollar = true;
373  if (accum <= 0 || accum > NL_ARGMAX)
374  goto bad_format;
375  if (afterstar)
376  {
377  if (argtypes[accum] &&
378  argtypes[accum] != ATYPE_INT)
379  goto bad_format;
380  argtypes[accum] = ATYPE_INT;
381  last_dollar = Max(last_dollar, accum);
382  afterstar = false;
383  }
384  else
385  fmtpos = accum;
386  accum = 0;
387  goto nextch1;
388  case 'l':
389  if (longflag)
390  longlongflag = 1;
391  else
392  longflag = 1;
393  goto nextch1;
394  case 'z':
395 #if SIZEOF_SIZE_T == 8
396 #ifdef HAVE_LONG_INT_64
397  longflag = 1;
398 #elif defined(HAVE_LONG_LONG_INT_64)
399  longlongflag = 1;
400 #else
401 #error "Don't know how to print 64bit integers"
402 #endif
403 #else
404  /* assume size_t is same size as int */
405 #endif
406  goto nextch1;
407  case 'h':
408  case '\'':
409  /* ignore these */
410  goto nextch1;
411  case 'd':
412  case 'i':
413  case 'o':
414  case 'u':
415  case 'x':
416  case 'X':
417  if (fmtpos)
418  {
419  PrintfArgType atype;
420 
421  if (longlongflag)
422  atype = ATYPE_LONGLONG;
423  else if (longflag)
424  atype = ATYPE_LONG;
425  else
426  atype = ATYPE_INT;
427  if (argtypes[fmtpos] &&
428  argtypes[fmtpos] != atype)
429  goto bad_format;
430  argtypes[fmtpos] = atype;
431  last_dollar = Max(last_dollar, fmtpos);
432  }
433  else
434  have_non_dollar = true;
435  break;
436  case 'c':
437  if (fmtpos)
438  {
439  if (argtypes[fmtpos] &&
440  argtypes[fmtpos] != ATYPE_INT)
441  goto bad_format;
442  argtypes[fmtpos] = ATYPE_INT;
443  last_dollar = Max(last_dollar, fmtpos);
444  }
445  else
446  have_non_dollar = true;
447  break;
448  case 's':
449  case 'p':
450  if (fmtpos)
451  {
452  if (argtypes[fmtpos] &&
453  argtypes[fmtpos] != ATYPE_CHARPTR)
454  goto bad_format;
455  argtypes[fmtpos] = ATYPE_CHARPTR;
456  last_dollar = Max(last_dollar, fmtpos);
457  }
458  else
459  have_non_dollar = true;
460  break;
461  case 'e':
462  case 'E':
463  case 'f':
464  case 'g':
465  case 'G':
466  if (fmtpos)
467  {
468  if (argtypes[fmtpos] &&
469  argtypes[fmtpos] != ATYPE_DOUBLE)
470  goto bad_format;
471  argtypes[fmtpos] = ATYPE_DOUBLE;
472  last_dollar = Max(last_dollar, fmtpos);
473  }
474  else
475  have_non_dollar = true;
476  break;
477  case '%':
478  break;
479  }
480 
481  /*
482  * If we finish the spec with afterstar still set, there's a
483  * non-dollar star in there.
484  */
485  if (afterstar)
486  have_non_dollar = true;
487  }
488 
489  /* Per spec, you use either all dollar or all not. */
490  if (have_dollar && have_non_dollar)
491  goto bad_format;
492 
493  /*
494  * In dollar mode, collect the arguments in physical order.
495  */
496  for (i = 1; i <= last_dollar; i++)
497  {
498  switch (argtypes[i])
499  {
500  case ATYPE_NONE:
501  goto bad_format;
502  case ATYPE_INT:
503  argvalues[i].i = va_arg(args, int);
504  break;
505  case ATYPE_LONG:
506  argvalues[i].l = va_arg(args, long);
507  break;
508  case ATYPE_LONGLONG:
509  argvalues[i].ll = va_arg(args, int64);
510  break;
511  case ATYPE_DOUBLE:
512  argvalues[i].d = va_arg(args, double);
513  break;
514  case ATYPE_CHARPTR:
515  argvalues[i].cptr = va_arg(args, char *);
516  break;
517  }
518  }
519 
520  /*
521  * At last we can parse the format for real.
522  */
523  format = format_start;
524  while ((ch = *format++) != '\0')
525  {
526  if (target->failed)
527  break;
528 
529  if (ch != '%')
530  {
531  dopr_outch(ch, target);
532  continue;
533  }
534  fieldwidth = precision = zpad = leftjust = forcesign = 0;
535  longflag = longlongflag = pointflag = 0;
536  fmtpos = accum = 0;
537  have_star = afterstar = false;
538 nextch2:
539  ch = *format++;
540  if (ch == '\0')
541  break; /* illegal, but we don't complain */
542  switch (ch)
543  {
544  case '-':
545  leftjust = 1;
546  goto nextch2;
547  case '+':
548  forcesign = 1;
549  goto nextch2;
550  case '0':
551  /* set zero padding if no nonzero digits yet */
552  if (accum == 0 && !pointflag)
553  zpad = '0';
554  /* FALL THRU */
555  case '1':
556  case '2':
557  case '3':
558  case '4':
559  case '5':
560  case '6':
561  case '7':
562  case '8':
563  case '9':
564  accum = accum * 10 + (ch - '0');
565  goto nextch2;
566  case '.':
567  if (have_star)
568  have_star = false;
569  else
570  fieldwidth = accum;
571  pointflag = 1;
572  accum = 0;
573  goto nextch2;
574  case '*':
575  if (have_dollar)
576  {
577  /* process value after reading n$ */
578  afterstar = true;
579  }
580  else
581  {
582  /* fetch and process value now */
583  int starval = va_arg(args, int);
584 
585  if (pointflag)
586  {
587  precision = starval;
588  if (precision < 0)
589  {
590  precision = 0;
591  pointflag = 0;
592  }
593  }
594  else
595  {
596  fieldwidth = starval;
597  if (fieldwidth < 0)
598  {
599  leftjust = 1;
600  fieldwidth = -fieldwidth;
601  }
602  }
603  }
604  have_star = true;
605  accum = 0;
606  goto nextch2;
607  case '$':
608  if (afterstar)
609  {
610  /* fetch and process star value */
611  int starval = argvalues[accum].i;
612 
613  if (pointflag)
614  {
615  precision = starval;
616  if (precision < 0)
617  {
618  precision = 0;
619  pointflag = 0;
620  }
621  }
622  else
623  {
624  fieldwidth = starval;
625  if (fieldwidth < 0)
626  {
627  leftjust = 1;
628  fieldwidth = -fieldwidth;
629  }
630  }
631  afterstar = false;
632  }
633  else
634  fmtpos = accum;
635  accum = 0;
636  goto nextch2;
637  case 'l':
638  if (longflag)
639  longlongflag = 1;
640  else
641  longflag = 1;
642  goto nextch2;
643  case 'z':
644 #if SIZEOF_SIZE_T == 8
645 #ifdef HAVE_LONG_INT_64
646  longflag = 1;
647 #elif defined(HAVE_LONG_LONG_INT_64)
648  longlongflag = 1;
649 #else
650 #error "Don't know how to print 64bit integers"
651 #endif
652 #else
653  /* assume size_t is same size as int */
654 #endif
655  goto nextch2;
656  case 'h':
657  case '\'':
658  /* ignore these */
659  goto nextch2;
660  case 'd':
661  case 'i':
662  if (!have_star)
663  {
664  if (pointflag)
665  precision = accum;
666  else
667  fieldwidth = accum;
668  }
669  if (have_dollar)
670  {
671  if (longlongflag)
672  numvalue = argvalues[fmtpos].ll;
673  else if (longflag)
674  numvalue = argvalues[fmtpos].l;
675  else
676  numvalue = argvalues[fmtpos].i;
677  }
678  else
679  {
680  if (longlongflag)
681  numvalue = va_arg(args, int64);
682  else if (longflag)
683  numvalue = va_arg(args, long);
684  else
685  numvalue = va_arg(args, int);
686  }
687  fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
688  precision, pointflag, target);
689  break;
690  case 'o':
691  case 'u':
692  case 'x':
693  case 'X':
694  if (!have_star)
695  {
696  if (pointflag)
697  precision = accum;
698  else
699  fieldwidth = accum;
700  }
701  if (have_dollar)
702  {
703  if (longlongflag)
704  numvalue = (uint64) argvalues[fmtpos].ll;
705  else if (longflag)
706  numvalue = (unsigned long) argvalues[fmtpos].l;
707  else
708  numvalue = (unsigned int) argvalues[fmtpos].i;
709  }
710  else
711  {
712  if (longlongflag)
713  numvalue = (uint64) va_arg(args, int64);
714  else if (longflag)
715  numvalue = (unsigned long) va_arg(args, long);
716  else
717  numvalue = (unsigned int) va_arg(args, int);
718  }
719  fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
720  precision, pointflag, target);
721  break;
722  case 'c':
723  if (!have_star)
724  {
725  if (pointflag)
726  precision = accum;
727  else
728  fieldwidth = accum;
729  }
730  if (have_dollar)
731  cvalue = (unsigned char) argvalues[fmtpos].i;
732  else
733  cvalue = (unsigned char) va_arg(args, int);
734  fmtchar(cvalue, leftjust, fieldwidth, target);
735  break;
736  case 's':
737  if (!have_star)
738  {
739  if (pointflag)
740  precision = accum;
741  else
742  fieldwidth = accum;
743  }
744  if (have_dollar)
745  strvalue = argvalues[fmtpos].cptr;
746  else
747  strvalue = va_arg(args, char *);
748  /* Whine if someone tries to print a NULL string */
749  Assert(strvalue != NULL);
750  fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag,
751  target);
752  break;
753  case 'p':
754  /* fieldwidth/leftjust are ignored ... */
755  if (have_dollar)
756  strvalue = argvalues[fmtpos].cptr;
757  else
758  strvalue = va_arg(args, char *);
759  fmtptr((void *) strvalue, target);
760  break;
761  case 'e':
762  case 'E':
763  case 'f':
764  case 'g':
765  case 'G':
766  if (!have_star)
767  {
768  if (pointflag)
769  precision = accum;
770  else
771  fieldwidth = accum;
772  }
773  if (have_dollar)
774  fvalue = argvalues[fmtpos].d;
775  else
776  fvalue = va_arg(args, double);
777  fmtfloat(fvalue, ch, forcesign, leftjust,
778  fieldwidth, zpad,
779  precision, pointflag,
780  target);
781  break;
782  case '%':
783  dopr_outch('%', target);
784  break;
785  }
786  }
787 
788  return;
789 
790 bad_format:
791  errno = EINVAL;
792  target->failed = true;
793 }
794 
795 static void
796 fmtstr(char *value, int leftjust, int minlen, int maxwidth,
797  int pointflag, PrintfTarget *target)
798 {
799  int padlen,
800  vallen; /* amount to pad */
801 
802  /*
803  * If a maxwidth (precision) is specified, we must not fetch more bytes
804  * than that.
805  */
806  if (pointflag)
807  vallen = strnlen(value, maxwidth);
808  else
809  vallen = strlen(value);
810 
811  adjust_padlen(minlen, vallen, leftjust, &padlen);
812 
813  while (padlen > 0)
814  {
815  dopr_outch(' ', target);
816  --padlen;
817  }
818 
819  dostr(value, vallen, target);
820 
821  trailing_pad(&padlen, target);
822 }
823 
824 static void
825 fmtptr(void *value, PrintfTarget *target)
826 {
827  int vallen;
828  char convert[64];
829 
830  /* we rely on regular C library's sprintf to do the basic conversion */
831  vallen = sprintf(convert, "%p", value);
832  if (vallen < 0)
833  target->failed = true;
834  else
835  dostr(convert, vallen, target);
836 }
837 
838 static void
839 fmtint(int64 value, char type, int forcesign, int leftjust,
840  int minlen, int zpad, int precision, int pointflag,
841  PrintfTarget *target)
842 {
843  uint64 base;
844  int dosign;
845  const char *cvt = "0123456789abcdef";
846  int signvalue = 0;
847  char convert[64];
848  int vallen = 0;
849  int padlen = 0; /* amount to pad */
850  int zeropad; /* extra leading zeroes */
851 
852  switch (type)
853  {
854  case 'd':
855  case 'i':
856  base = 10;
857  dosign = 1;
858  break;
859  case 'o':
860  base = 8;
861  dosign = 0;
862  break;
863  case 'u':
864  base = 10;
865  dosign = 0;
866  break;
867  case 'x':
868  base = 16;
869  dosign = 0;
870  break;
871  case 'X':
872  cvt = "0123456789ABCDEF";
873  base = 16;
874  dosign = 0;
875  break;
876  default:
877  return; /* keep compiler quiet */
878  }
879 
880  /* Handle +/- */
881  if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
882  value = -value;
883 
884  /*
885  * SUS: the result of converting 0 with an explicit precision of 0 is no
886  * characters
887  */
888  if (value == 0 && pointflag && precision == 0)
889  vallen = 0;
890  else
891  {
892  /* make integer string */
893  uint64 uvalue = (uint64) value;
894 
895  do
896  {
897  convert[vallen++] = cvt[uvalue % base];
898  uvalue = uvalue / base;
899  } while (uvalue);
900  }
901 
902  zeropad = Max(0, precision - vallen);
903 
904  adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen);
905 
906  leading_pad(zpad, &signvalue, &padlen, target);
907 
908  while (zeropad-- > 0)
909  dopr_outch('0', target);
910 
911  while (vallen > 0)
912  dopr_outch(convert[--vallen], target);
913 
914  trailing_pad(&padlen, target);
915 }
916 
917 static void
918 fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
919 {
920  int padlen = 0; /* amount to pad */
921 
922  adjust_padlen(minlen, 1, leftjust, &padlen);
923 
924  while (padlen > 0)
925  {
926  dopr_outch(' ', target);
927  --padlen;
928  }
929 
930  dopr_outch(value, target);
931 
932  trailing_pad(&padlen, target);
933 }
934 
935 static void
936 fmtfloat(double value, char type, int forcesign, int leftjust,
937  int minlen, int zpad, int precision, int pointflag,
938  PrintfTarget *target)
939 {
940  int signvalue = 0;
941  int prec;
942  int vallen;
943  char fmt[32];
944  char convert[1024];
945  int zeropadlen = 0; /* amount to pad with zeroes */
946  int padlen = 0; /* amount to pad with spaces */
947 
948  /*
949  * We rely on the regular C library's sprintf to do the basic conversion,
950  * then handle padding considerations here.
951  *
952  * The dynamic range of "double" is about 1E+-308 for IEEE math, and not
953  * too wildly more than that with other hardware. In "f" format, sprintf
954  * could therefore generate at most 308 characters to the left of the
955  * decimal point; while we need to allow the precision to get as high as
956  * 308+17 to ensure that we don't truncate significant digits from very
957  * small values. To handle both these extremes, we use a buffer of 1024
958  * bytes and limit requested precision to 350 digits; this should prevent
959  * buffer overrun even with non-IEEE math. If the original precision
960  * request was more than 350, separately pad with zeroes.
961  */
962  if (precision < 0) /* cover possible overflow of "accum" */
963  precision = 0;
964  prec = Min(precision, 350);
965 
966  if (pointflag)
967  {
968  if (sprintf(fmt, "%%.%d%c", prec, type) < 0)
969  goto fail;
970  zeropadlen = precision - prec;
971  }
972  else if (sprintf(fmt, "%%%c", type) < 0)
973  goto fail;
974 
975  if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue))
976  value = -value;
977 
978  vallen = sprintf(convert, fmt, value);
979  if (vallen < 0)
980  goto fail;
981 
982  /* If it's infinity or NaN, forget about doing any zero-padding */
983  if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1]))
984  zeropadlen = 0;
985 
986  adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen);
987 
988  leading_pad(zpad, &signvalue, &padlen, target);
989 
990  if (zeropadlen > 0)
991  {
992  /* If 'e' or 'E' format, inject zeroes before the exponent */
993  char *epos = strrchr(convert, 'e');
994 
995  if (!epos)
996  epos = strrchr(convert, 'E');
997  if (epos)
998  {
999  /* pad after exponent */
1000  dostr(convert, epos - convert, target);
1001  while (zeropadlen-- > 0)
1002  dopr_outch('0', target);
1003  dostr(epos, vallen - (epos - convert), target);
1004  }
1005  else
1006  {
1007  /* no exponent, pad after the digits */
1008  dostr(convert, vallen, target);
1009  while (zeropadlen-- > 0)
1010  dopr_outch('0', target);
1011  }
1012  }
1013  else
1014  {
1015  /* no zero padding, just emit the number as-is */
1016  dostr(convert, vallen, target);
1017  }
1018 
1019  trailing_pad(&padlen, target);
1020  return;
1021 
1022 fail:
1023  target->failed = true;
1024 }
1025 
1026 static void
1027 dostr(const char *str, int slen, PrintfTarget *target)
1028 {
1029  while (slen > 0)
1030  {
1031  int avail;
1032 
1033  if (target->bufend != NULL)
1034  avail = target->bufend - target->bufptr;
1035  else
1036  avail = slen;
1037  if (avail <= 0)
1038  {
1039  /* buffer full, can we dump to stream? */
1040  if (target->stream == NULL)
1041  return; /* no, lose the data */
1042  flushbuffer(target);
1043  continue;
1044  }
1045  avail = Min(avail, slen);
1046  memmove(target->bufptr, str, avail);
1047  target->bufptr += avail;
1048  str += avail;
1049  slen -= avail;
1050  }
1051 }
1052 
1053 static void
1055 {
1056  if (target->bufend != NULL && target->bufptr >= target->bufend)
1057  {
1058  /* buffer full, can we dump to stream? */
1059  if (target->stream == NULL)
1060  return; /* no, lose the data */
1061  flushbuffer(target);
1062  }
1063  *(target->bufptr++) = c;
1064 }
1065 
1066 
1067 static int
1068 adjust_sign(int is_negative, int forcesign, int *signvalue)
1069 {
1070  if (is_negative)
1071  {
1072  *signvalue = '-';
1073  return true;
1074  }
1075  else if (forcesign)
1076  *signvalue = '+';
1077  return false;
1078 }
1079 
1080 
1081 static void
1082 adjust_padlen(int minlen, int vallen, int leftjust, int *padlen)
1083 {
1084  *padlen = minlen - vallen;
1085  if (*padlen < 0)
1086  *padlen = 0;
1087  if (leftjust)
1088  *padlen = -(*padlen);
1089 }
1090 
1091 
1092 static void
1093 leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target)
1094 {
1095  if (*padlen > 0 && zpad)
1096  {
1097  if (*signvalue)
1098  {
1099  dopr_outch(*signvalue, target);
1100  --(*padlen);
1101  *signvalue = 0;
1102  }
1103  while (*padlen > 0)
1104  {
1105  dopr_outch(zpad, target);
1106  --(*padlen);
1107  }
1108  }
1109  while (*padlen > (*signvalue != 0))
1110  {
1111  dopr_outch(' ', target);
1112  --(*padlen);
1113  }
1114  if (*signvalue)
1115  {
1116  dopr_outch(*signvalue, target);
1117  if (*padlen > 0)
1118  --(*padlen);
1119  else if (*padlen < 0)
1120  ++(*padlen);
1121  }
1122 }
1123 
1124 
1125 static void
1126 trailing_pad(int *padlen, PrintfTarget *target)
1127 {
1128  while (*padlen < 0)
1129  {
1130  dopr_outch(' ', target);
1131  ++(*padlen);
1132  }
1133 }
char * bufend
Definition: snprintf.c:112
static void dopr_outch(int c, PrintfTarget *target)
Definition: snprintf.c:1054
static struct @130 value
static int pg_vsprintf(char *str, const char *fmt, va_list args)
Definition: snprintf.c:179
int pg_snprintf(char *str, size_t count, const char *fmt,...)
Definition: snprintf.c:167
int pg_vfprintf(FILE *stream, const char *fmt, va_list args)
Definition: snprintf.c:208
static void fmtptr(void *value, PrintfTarget *target)
Definition: snprintf.c:825
static void fmtint(int64 value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target)
Definition: snprintf.c:839
#define Min(x, y)
Definition: c.h:846
static void dostr(const char *str, int slen, PrintfTarget *target)
Definition: snprintf.c:1027
static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
Definition: snprintf.c:918
#define MemSet(start, val, len)
Definition: c.h:897
char * bufstart
Definition: snprintf.c:111
static void convert(const int32 val, char *const buf)
Definition: zic.c:1812
static void flushbuffer(PrintfTarget *target)
Definition: snprintf.c:258
char * c
#define memmove(d, s, c)
Definition: c.h:1089
int pg_printf(const char *fmt,...)
Definition: snprintf.c:242
int pg_sprintf(char *str, const char *fmt,...)
Definition: snprintf.c:196
char * cptr
Definition: snprintf.c:141
FILE * stream
Definition: snprintf.c:114
int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
Definition: snprintf.c:150
static int adjust_sign(int is_negative, int forcesign, int *signvalue)
Definition: snprintf.c:1068
bool failed
Definition: snprintf.c:116
static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target)
Definition: snprintf.c:796
#define Max(x, y)
Definition: c.h:840
PrintfArgType
Definition: snprintf.c:125
#define Assert(condition)
Definition: c.h:688
#define NL_ARGMAX
Definition: snprintf.c:47
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
static void dopr(PrintfTarget *target, const char *format, va_list args)
Definition: snprintf.c:298
size_t strnlen(const char *str, size_t maxlen)
Definition: strnlen.c:26
static void leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target)
Definition: snprintf.c:1093
int i
static char format
Definition: pg_basebackup.c:81
static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen)
Definition: snprintf.c:1082
char * bufptr
Definition: snprintf.c:110
int pg_fprintf(FILE *stream, const char *fmt,...)
Definition: snprintf.c:230
static void trailing_pad(int *padlen, PrintfTarget *target)
Definition: snprintf.c:1126
static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target)
Definition: snprintf.c:936