PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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  fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag,
749  target);
750  break;
751  case 'p':
752  /* fieldwidth/leftjust are ignored ... */
753  if (have_dollar)
754  strvalue = argvalues[fmtpos].cptr;
755  else
756  strvalue = va_arg(args, char *);
757  fmtptr((void *) strvalue, target);
758  break;
759  case 'e':
760  case 'E':
761  case 'f':
762  case 'g':
763  case 'G':
764  if (!have_star)
765  {
766  if (pointflag)
767  precision = accum;
768  else
769  fieldwidth = accum;
770  }
771  if (have_dollar)
772  fvalue = argvalues[fmtpos].d;
773  else
774  fvalue = va_arg(args, double);
775  fmtfloat(fvalue, ch, forcesign, leftjust,
776  fieldwidth, zpad,
777  precision, pointflag,
778  target);
779  break;
780  case '%':
781  dopr_outch('%', target);
782  break;
783  }
784  }
785 
786  return;
787 
788 bad_format:
789  errno = EINVAL;
790  target->failed = true;
791 }
792 
793 static size_t
794 pg_strnlen(const char *str, size_t maxlen)
795 {
796  const char *p = str;
797 
798  while (maxlen-- > 0 && *p)
799  p++;
800  return p - str;
801 }
802 
803 static void
804 fmtstr(char *value, int leftjust, int minlen, int maxwidth,
805  int pointflag, PrintfTarget *target)
806 {
807  int padlen,
808  vallen; /* amount to pad */
809 
810  /*
811  * If a maxwidth (precision) is specified, we must not fetch more bytes
812  * than that.
813  */
814  if (pointflag)
815  vallen = pg_strnlen(value, maxwidth);
816  else
817  vallen = strlen(value);
818 
819  adjust_padlen(minlen, vallen, leftjust, &padlen);
820 
821  while (padlen > 0)
822  {
823  dopr_outch(' ', target);
824  --padlen;
825  }
826 
827  dostr(value, vallen, target);
828 
829  trailing_pad(&padlen, target);
830 }
831 
832 static void
833 fmtptr(void *value, PrintfTarget *target)
834 {
835  int vallen;
836  char convert[64];
837 
838  /* we rely on regular C library's sprintf to do the basic conversion */
839  vallen = sprintf(convert, "%p", value);
840  if (vallen < 0)
841  target->failed = true;
842  else
843  dostr(convert, vallen, target);
844 }
845 
846 static void
847 fmtint(int64 value, char type, int forcesign, int leftjust,
848  int minlen, int zpad, int precision, int pointflag,
849  PrintfTarget *target)
850 {
851  uint64 base;
852  int dosign;
853  const char *cvt = "0123456789abcdef";
854  int signvalue = 0;
855  char convert[64];
856  int vallen = 0;
857  int padlen = 0; /* amount to pad */
858  int zeropad; /* extra leading zeroes */
859 
860  switch (type)
861  {
862  case 'd':
863  case 'i':
864  base = 10;
865  dosign = 1;
866  break;
867  case 'o':
868  base = 8;
869  dosign = 0;
870  break;
871  case 'u':
872  base = 10;
873  dosign = 0;
874  break;
875  case 'x':
876  base = 16;
877  dosign = 0;
878  break;
879  case 'X':
880  cvt = "0123456789ABCDEF";
881  base = 16;
882  dosign = 0;
883  break;
884  default:
885  return; /* keep compiler quiet */
886  }
887 
888  /* Handle +/- */
889  if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
890  value = -value;
891 
892  /*
893  * SUS: the result of converting 0 with an explicit precision of 0 is no
894  * characters
895  */
896  if (value == 0 && pointflag && precision == 0)
897  vallen = 0;
898  else
899  {
900  /* make integer string */
901  uint64 uvalue = (uint64) value;
902 
903  do
904  {
905  convert[vallen++] = cvt[uvalue % base];
906  uvalue = uvalue / base;
907  } while (uvalue);
908  }
909 
910  zeropad = Max(0, precision - vallen);
911 
912  adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen);
913 
914  leading_pad(zpad, &signvalue, &padlen, target);
915 
916  while (zeropad-- > 0)
917  dopr_outch('0', target);
918 
919  while (vallen > 0)
920  dopr_outch(convert[--vallen], target);
921 
922  trailing_pad(&padlen, target);
923 }
924 
925 static void
926 fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
927 {
928  int padlen = 0; /* amount to pad */
929 
930  adjust_padlen(minlen, 1, leftjust, &padlen);
931 
932  while (padlen > 0)
933  {
934  dopr_outch(' ', target);
935  --padlen;
936  }
937 
938  dopr_outch(value, target);
939 
940  trailing_pad(&padlen, target);
941 }
942 
943 static void
944 fmtfloat(double value, char type, int forcesign, int leftjust,
945  int minlen, int zpad, int precision, int pointflag,
946  PrintfTarget *target)
947 {
948  int signvalue = 0;
949  int prec;
950  int vallen;
951  char fmt[32];
952  char convert[1024];
953  int zeropadlen = 0; /* amount to pad with zeroes */
954  int padlen = 0; /* amount to pad with spaces */
955 
956  /*
957  * We rely on the regular C library's sprintf to do the basic conversion,
958  * then handle padding considerations here.
959  *
960  * The dynamic range of "double" is about 1E+-308 for IEEE math, and not
961  * too wildly more than that with other hardware. In "f" format, sprintf
962  * could therefore generate at most 308 characters to the left of the
963  * decimal point; while we need to allow the precision to get as high as
964  * 308+17 to ensure that we don't truncate significant digits from very
965  * small values. To handle both these extremes, we use a buffer of 1024
966  * bytes and limit requested precision to 350 digits; this should prevent
967  * buffer overrun even with non-IEEE math. If the original precision
968  * request was more than 350, separately pad with zeroes.
969  */
970  if (precision < 0) /* cover possible overflow of "accum" */
971  precision = 0;
972  prec = Min(precision, 350);
973 
974  if (pointflag)
975  {
976  if (sprintf(fmt, "%%.%d%c", prec, type) < 0)
977  goto fail;
978  zeropadlen = precision - prec;
979  }
980  else if (sprintf(fmt, "%%%c", type) < 0)
981  goto fail;
982 
983  if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue))
984  value = -value;
985 
986  vallen = sprintf(convert, fmt, value);
987  if (vallen < 0)
988  goto fail;
989 
990  /* If it's infinity or NaN, forget about doing any zero-padding */
991  if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1]))
992  zeropadlen = 0;
993 
994  adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen);
995 
996  leading_pad(zpad, &signvalue, &padlen, target);
997 
998  if (zeropadlen > 0)
999  {
1000  /* If 'e' or 'E' format, inject zeroes before the exponent */
1001  char *epos = strrchr(convert, 'e');
1002 
1003  if (!epos)
1004  epos = strrchr(convert, 'E');
1005  if (epos)
1006  {
1007  /* pad after exponent */
1008  dostr(convert, epos - convert, target);
1009  while (zeropadlen-- > 0)
1010  dopr_outch('0', target);
1011  dostr(epos, vallen - (epos - convert), target);
1012  }
1013  else
1014  {
1015  /* no exponent, pad after the digits */
1016  dostr(convert, vallen, target);
1017  while (zeropadlen-- > 0)
1018  dopr_outch('0', target);
1019  }
1020  }
1021  else
1022  {
1023  /* no zero padding, just emit the number as-is */
1024  dostr(convert, vallen, target);
1025  }
1026 
1027  trailing_pad(&padlen, target);
1028  return;
1029 
1030 fail:
1031  target->failed = true;
1032 }
1033 
1034 static void
1035 dostr(const char *str, int slen, PrintfTarget *target)
1036 {
1037  while (slen > 0)
1038  {
1039  int avail;
1040 
1041  if (target->bufend != NULL)
1042  avail = target->bufend - target->bufptr;
1043  else
1044  avail = slen;
1045  if (avail <= 0)
1046  {
1047  /* buffer full, can we dump to stream? */
1048  if (target->stream == NULL)
1049  return; /* no, lose the data */
1050  flushbuffer(target);
1051  continue;
1052  }
1053  avail = Min(avail, slen);
1054  memmove(target->bufptr, str, avail);
1055  target->bufptr += avail;
1056  str += avail;
1057  slen -= avail;
1058  }
1059 }
1060 
1061 static void
1063 {
1064  if (target->bufend != NULL && target->bufptr >= target->bufend)
1065  {
1066  /* buffer full, can we dump to stream? */
1067  if (target->stream == NULL)
1068  return; /* no, lose the data */
1069  flushbuffer(target);
1070  }
1071  *(target->bufptr++) = c;
1072 }
1073 
1074 
1075 static int
1076 adjust_sign(int is_negative, int forcesign, int *signvalue)
1077 {
1078  if (is_negative)
1079  {
1080  *signvalue = '-';
1081  return true;
1082  }
1083  else if (forcesign)
1084  *signvalue = '+';
1085  return false;
1086 }
1087 
1088 
1089 static void
1090 adjust_padlen(int minlen, int vallen, int leftjust, int *padlen)
1091 {
1092  *padlen = minlen - vallen;
1093  if (*padlen < 0)
1094  *padlen = 0;
1095  if (leftjust)
1096  *padlen = -(*padlen);
1097 }
1098 
1099 
1100 static void
1101 leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target)
1102 {
1103  if (*padlen > 0 && zpad)
1104  {
1105  if (*signvalue)
1106  {
1107  dopr_outch(*signvalue, target);
1108  --(*padlen);
1109  *signvalue = 0;
1110  }
1111  while (*padlen > 0)
1112  {
1113  dopr_outch(zpad, target);
1114  --(*padlen);
1115  }
1116  }
1117  while (*padlen > (*signvalue != 0))
1118  {
1119  dopr_outch(' ', target);
1120  --(*padlen);
1121  }
1122  if (*signvalue)
1123  {
1124  dopr_outch(*signvalue, target);
1125  if (*padlen > 0)
1126  --(*padlen);
1127  else if (*padlen < 0)
1128  ++(*padlen);
1129  }
1130 }
1131 
1132 
1133 static void
1134 trailing_pad(int *padlen, PrintfTarget *target)
1135 {
1136  while (*padlen < 0)
1137  {
1138  dopr_outch(' ', target);
1139  ++(*padlen);
1140  }
1141 }
char * bufend
Definition: snprintf.c:112
static void dopr_outch(int c, PrintfTarget *target)
Definition: snprintf.c:1062
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:833
static void fmtint(int64 value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target)
Definition: snprintf.c:847
#define Min(x, y)
Definition: c.h:795
static void dostr(const char *str, int slen, PrintfTarget *target)
Definition: snprintf.c:1035
static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
Definition: snprintf.c:926
#define MemSet(start, val, len)
Definition: c.h:846
char * bufstart
Definition: snprintf.c:111
static void convert(const int32 val, char *const buf)
Definition: zic.c:1810
static void flushbuffer(PrintfTarget *target)
Definition: snprintf.c:258
static struct @121 value
char * c
#define memmove(d, s, c)
Definition: c.h:1047
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:1076
bool failed
Definition: snprintf.c:116
static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target)
Definition: snprintf.c:804
#define Max(x, y)
Definition: c.h:789
PrintfArgType
Definition: snprintf.c:125
#define NL_ARGMAX
Definition: snprintf.c:47
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
static void dopr(PrintfTarget *target, const char *format, va_list args)
Definition: snprintf.c:298
static size_t pg_strnlen(const char *str, size_t maxlen)
Definition: snprintf.c:794
static void leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target)
Definition: snprintf.c:1101
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:1090
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:1134
static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target)
Definition: snprintf.c:944