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