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