1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 /*
38  * IMPORTANT NOTE:
39  * --------------
40  * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
41  * paragraph 3 above is now null and void.
42  */
43 
44 /* SNPRINTF.C
45  * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module.
46  *      http://www.mibsoftware.com
47  * Mib Software does not warrant this software any differently than the
48  * University of California, Berkeley as described above.  All warranties
49  * are disclaimed.  Use this software at your own risk.
50  *
51  *      All code referencing FILE * functions was eliminated, since it could
52  *      never be called.  All header files and necessary files are collapsed
53  *      into one file, internal functions are declared static.  This should
54  *      allow inclusion into libraries with less chance of namespace collisions.
55  *
56  *      snprintf should be the only externally visible item.
57  *
58  *      As of 7-31-97 FLOATING_POINT is NOT provided.  The code is somewhat
59  *        non-portable, so it is disabled.
60  */
61 
62 /* Define FLOATING_POINT to get floating point. */
63 /*
64 #define	FLOATING_POINT
65 */
66 
67 #include <sys/types.h>
68 #define u_long unsigned long
69 #define u_short unsigned short
70 #define u_int unsigned int
71 
72 #undef __P
73 #if defined(__STDC__)
74 # include <stdarg.h>
75 # if !defined(__P)
76 #  define __P(x) x
77 # endif
78 #else
79 # define __P(x) ()
80 # if !defined(const)
81 #  define const
82 # endif
83 # include <varargs.h>
84 #endif
85 #ifndef _BSD_VA_LIST_
86 #define	_BSD_VA_LIST_ va_list
87 #endif
88 
89 #ifdef __STDC__
90 # include <limits.h>
91 #else
92 # ifndef LONG_MAX
93 #  ifdef HAVE_LIMITS_H
94 #   include <limits.h>
95 #  else
96     /* assuming 32bit(2's compliment) long */
97 #   define LONG_MAX 2147483647
98 #  endif
99 # endif
100 #endif
101 
102 #if defined(__hpux) && !defined(__GNUC__)
103 #define const
104 #endif
105 
106 #if defined(sgi)
107 #undef __const
108 #define __const
109 #endif /* People who don't like const sys_error */
110 
111 #include <stddef.h>
112 
113 #ifndef NULL
114 #define	NULL	0
115 #endif
116 
117 /*
118  * NB: to fit things in six character monocase externals, the stdio
119  * code uses the prefix `__s' for stdio objects, typically followed
120  * by a three-character attempt at a mnemonic.
121  */
122 
123 /* stdio buffers */
124 struct __sbuf {
125 	unsigned char *_base;
126 	int	_size;
127 };
128 
129 
130 /*
131  * stdio state variables.
132  *
133  * The following always hold:
134  *
135  *	if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
136  *		_lbfsize is -_bf._size, else _lbfsize is 0
137  *	if _flags&__SRD, _w is 0
138  *	if _flags&__SWR, _r is 0
139  *
140  * This ensures that the getc and putc macros (or inline functions) never
141  * try to write or read from a file that is in `read' or `write' mode.
142  * (Moreover, they can, and do, automatically switch from read mode to
143  * write mode, and back, on "r+" and "w+" files.)
144  *
145  * _lbfsize is used only to make the inline line-buffered output stream
146  * code as compact as possible.
147  *
148  * _ub, _up, and _ur are used when ungetc() pushes back more characters
149  * than fit in the current _bf, or when ungetc() pushes back a character
150  * that does not match the previous one in _bf.  When this happens,
151  * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
152  * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
153  *
154  * NB: see WARNING above before changing the layout of this structure!
155  */
156 typedef	struct __sFILE {
157 	unsigned char *_p;	/* current position in (some) buffer */
158 	int	_r;		/* read space left for getc() */
159 	int	_w;		/* write space left for putc() */
160 	short	_flags;		/* flags, below; this FILE is free if 0 */
161 	short	_file;		/* fileno, if Unix descriptor, else -1 */
162 	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
163 	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
164 } FILE;
165 
166 
167 #define	__SLBF	0x0001		/* line buffered */
168 #define	__SNBF	0x0002		/* unbuffered */
169 #define	__SRD	0x0004		/* OK to read */
170 #define	__SWR	0x0008		/* OK to write */
171 	/* RD and WR are never simultaneously asserted */
172 #define	__SRW	0x0010		/* open for reading & writing */
173 #define	__SEOF	0x0020		/* found EOF */
174 #define	__SERR	0x0040		/* found error */
175 #define	__SMBF	0x0080		/* _buf is from malloc */
176 #define	__SAPP	0x0100		/* fdopen()ed in append mode */
177 #define	__SSTR	0x0200		/* this is an sprintf/snprintf string */
178 #define	__SOPT	0x0400		/* do fseek() optimisation */
179 #define	__SNPT	0x0800		/* do not do fseek() optimisation */
180 #define	__SOFF	0x1000		/* set iff _offset is in fact correct */
181 #define	__SMOD	0x2000		/* true => fgetln modified _p text */
182 
183 
184 #define	EOF	(-1)
185 
186 
187 #define	__sfeof(p)	(((p)->_flags & __SEOF) != 0)
188 #define	__sferror(p)	(((p)->_flags & __SERR) != 0)
189 #define	__sclearerr(p)	((void)((p)->_flags &= ~(__SERR|__SEOF)))
190 #define	__sfileno(p)	((p)->_file)
191 
192 #define	feof(p)		__sfeof(p)
193 #define	ferror(p)	__sferror(p)
194 #define	clearerr(p)	__sclearerr(p)
195 
196 #ifndef _ANSI_SOURCE
197 #define	fileno(p)	__sfileno(p)
198 #endif
199 
200 
201 #if defined(__hpux) && !defined(__GNUC__) || defined(__DECC)
202 #include <string.h>
203 #endif
204 
205 /*
206  * I/O descriptors for __sfvwrite().
207  */
208 struct __siov {
209 	void	*iov_base;
210 	size_t	iov_len;
211 };
212 struct __suio {
213 	struct	__siov *uio_iov;
214 	int	uio_iovcnt;
215 	int	uio_resid;
216 };
217 
218 /*
219  * Write some memory regions.  Return zero on success, EOF on error.
220  *
221  * This routine is large and unsightly, but most of the ugliness due
222  * to the three different kinds of output buffering is handled here.
223  */
BSD__sfvwrite(fp,uio)224 static BSD__sfvwrite(fp, uio)
225 	register FILE *fp;
226 	register struct __suio *uio;
227 {
228 	register size_t len;
229 	register char *p;
230 	register struct __siov *iov;
231 	register int w;
232 
233 	if ((len = uio->uio_resid) == 0)
234 		return (0);
235 #ifndef __hpux
236 #define	MIN(a, b) ((a) < (b) ? (a) : (b))
237 #endif
238 #define	COPY(n)	  (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
239 
240 	iov = uio->uio_iov;
241 	p = iov->iov_base;
242 	len = iov->iov_len;
243 	iov++;
244 #define GETIOV(extra_work) \
245 	while (len == 0) { \
246 		extra_work; \
247 		p = iov->iov_base; \
248 		len = iov->iov_len; \
249 		iov++; \
250 	}
251 	if (fp->_flags & __SNBF) {
252 	/* fjc 7-31-97 Will never happen.  We are working with
253 					   strings only
254 	*/
255 	} else if ((fp->_flags & __SLBF) == 0) {
256 	/*
257 		 * Fully buffered: fill partially full buffer, if any,
258 		 * and then flush.  If there is no partial buffer, write
259 		 * one _bf._size byte chunk directly (without copying).
260 		 *
261 		 * String output is a special case: write as many bytes
262 		 * as fit, but pretend we wrote everything.  This makes
263 		 * snprintf() return the number of bytes needed, rather
264 		 * than the number used, and avoids its write function
265 		 * (so that the write function can be invalid).
266 		 */
267 		do {
268 			GETIOV(;);
269 			w = fp->_w;
270 			if (fp->_flags & __SSTR) {
271 				if (len < w)
272 					w = len;
273 				COPY(w);	/* copy MIN(fp->_w,len), */
274 				fp->_w -= w;
275 				fp->_p += w;
276 				w = len;	/* but pretend copied all */
277 			} else {
278 				/* fjc 7-31-97 Will never happen.  We are working with
279 								   strings only
280 				*/
281 			}
282 			p += w;
283 			len -= w;
284 		} while ((uio->uio_resid -= w) != 0);
285 	} else {
286 		/* fjc 7-31-97 Will never happen.  We are working with
287 						   strings only
288 		*/
289 	}
290 	return (0);
291 
292 err:
293 	fp->_flags |= __SERR;
294 	return (EOF);
295 }
296 
297 /*
298  * Actual printf innards.
299  *
300  * This code is large and complicated...
301  */
302 
303 #if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__)
304 #include <stdlib.h>
305 #endif
306 
307 /*
308  * Flush out all the vectors defined by the given uio,
309  * then reset it so that it can be reused.
310  */
311 static int
BSD__sprint(fp,uio)312 BSD__sprint(fp, uio)
313 	FILE *fp;
314 	register struct __suio *uio;
315 {
316 	register int err;
317 
318 	if (uio->uio_resid == 0) {
319 		uio->uio_iovcnt = 0;
320 		return (0);
321 	}
322 	err = BSD__sfvwrite(fp, uio);
323 	uio->uio_resid = 0;
324 	uio->uio_iovcnt = 0;
325 	return (err);
326 }
327 
328 
329 /*
330  * Helper function for `fprintf to unbuffered unix file': creates a
331  * temporary buffer.  We only work on write-only files; this avoids
332  * worries about ungetc buffers and so forth.
333  */
334 static int
BSD__sbprintf(fp,fmt,ap)335 BSD__sbprintf(fp, fmt, ap)
336 	register FILE *fp;
337 	const char *fmt;
338 	va_list ap;
339 {
340 /* We don't support files. */
341 	return 0;
342 }
343 
344 
345 /*
346  * Macros for converting digits to letters and vice versa
347  */
348 #define	to_digit(c)	((c) - '0')
349 #define is_digit(c)	((unsigned)to_digit(c) <= 9)
350 #define	to_char(n)	((n) + '0')
351 
352 /*
353  * Convert an unsigned long to ASCII for printf purposes, returning
354  * a pointer to the first character of the string representation.
355  * Octal numbers can be forced to have a leading zero; hex numbers
356  * use the given digits.
357  */
358 static char *
BSD__ultoa(val,endp,base,octzero,xdigs)359 BSD__ultoa(val, endp, base, octzero, xdigs)
360 	register u_long val;
361 	char *endp;
362 	int base, octzero;
363 	char *xdigs;
364 {
365 	register char *cp = endp;
366 	register long sval;
367 
368 	/*
369 	 * Handle the three cases separately, in the hope of getting
370 	 * better/faster code.
371 	 */
372 	switch (base) {
373 	case 10:
374 		if (val < 10) {	/* many numbers are 1 digit */
375 			*--cp = to_char(val);
376 			return (cp);
377 		}
378 		/*
379 		 * On many machines, unsigned arithmetic is harder than
380 		 * signed arithmetic, so we do at most one unsigned mod and
381 		 * divide; this is sufficient to reduce the range of
382 		 * the incoming value to where signed arithmetic works.
383 		 */
384 		if (val > LONG_MAX) {
385 			*--cp = to_char(val % 10);
386 			sval = val / 10;
387 		} else
388 			sval = val;
389 		do {
390 			*--cp = to_char(sval % 10);
391 			sval /= 10;
392 		} while (sval != 0);
393 		break;
394 
395 	case 8:
396 		do {
397 			*--cp = to_char(val & 7);
398 			val >>= 3;
399 		} while (val);
400 		if (octzero && *cp != '0')
401 			*--cp = '0';
402 		break;
403 
404 	case 16:
405 		do {
406 			*--cp = xdigs[val & 15];
407 			val >>= 4;
408 		} while (val);
409 		break;
410 
411 	default:			/* oops */
412 		/*
413 		abort();
414 		*/
415 		break;	/* fjc 7-31-97.  Don't reference abort() here */
416 	}
417 	return (cp);
418 }
419 
420 #ifdef FLOATING_POINT
421 #include <math.h>
422 /* #include "floatio.h" */
423 
424 #ifndef MAXEXP
425 # define MAXEXP 1024
426 #endif
427 
428 #ifndef MAXFRACT
429 # define MAXFRACT 64
430 #endif
431 
432 #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
433 #define	DEFPREC		6
434 
435 static char *cvt __P((double, int, int, char *, int *, int, int *));
436 static int exponent __P((char *, int, int));
437 
438 #else /* no FLOATING_POINT */
439 
440 #define	BUF		68
441 
442 #endif /* FLOATING_POINT */
443 
444 
445 /*
446  * Flags used during conversion.
447  */
448 #define	ALT		0x001		/* alternate form */
449 #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
450 #define	LADJUST		0x004		/* left adjustment */
451 #define	LONGDBL		0x008		/* long double; unimplemented */
452 #define	LONGINT		0x010		/* long integer */
453 
454 #ifdef _HAVE_SANE_QUAD_
455 #define	QUADINT		0x020		/* quad integer */
456 #endif /* _HAVE_SANE_QUAD_ */
457 
458 #define	SHORTINT	0x040		/* short integer */
459 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
460 #define FPT		0x100		/* Floating point number */
461 static int
BSD_vfprintf(fp,fmt0,ap)462 BSD_vfprintf(fp, fmt0, ap)
463 	FILE *fp;
464 	const char *fmt0;
465 	va_list ap;
466 {
467 	register char *fmt;	/* format string */
468 	register int ch;	/* character from fmt */
469 	register int n;		/* handy integer (short term usage) */
470 	register char *cp;	/* handy char pointer (short term usage) */
471 	register struct __siov *iovp;/* for PRINT macro */
472 	register int flags;	/* flags as above */
473 	int ret;		/* return value accumulator */
474 	int width;		/* width from format (%8d), or 0 */
475 	int prec;		/* precision from format (%.3d), or -1 */
476 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
477 #ifdef FLOATING_POINT
478 	char softsign;		/* temporary negative sign for floats */
479 	double _double;		/* double precision arguments %[eEfgG] */
480 	int expt;		/* integer value of exponent */
481 	int expsize;		/* character count for expstr */
482 	int ndig;		/* actual number of digits returned by cvt */
483 	char expstr[7];		/* buffer for exponent string */
484 #endif
485 	u_long	ulval;		/* integer arguments %[diouxX] */
486 #ifdef _HAVE_SANE_QUAD_
487 	u_quad_t uqval;		/* %q integers */
488 #endif /* _HAVE_SANE_QUAD_ */
489 	int base;		/* base for [diouxX] conversion */
490 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
491 	int fieldsz;		/* field size expanded by sign, etc */
492 	int realsz;		/* field size expanded by dprec */
493 	int size;		/* size of converted field or string */
494 	char *xdigs;		/* digits for [xX] conversion */
495 #define NIOV 8
496 	struct __suio uio;	/* output information: summary */
497 	struct __siov iov[NIOV];/* ... and individual io vectors */
498 	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
499 	char ox[2];		/* space for 0x hex-prefix */
500 
501 	/*
502 	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
503 	 * fields occur frequently, increase PADSIZE and make the initialisers
504 	 * below longer.
505 	 */
506 #define	PADSIZE	16		/* pad chunk size */
507 	static char blanks[PADSIZE] =
508 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
509 	static char zeroes[PADSIZE] =
510 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
511 
512 	/*
513 	 * BEWARE, these `goto error' on error, and PAD uses `n'.
514 	 */
515 #define	PRINT(ptr, len) { \
516 	iovp->iov_base = (ptr); \
517 	iovp->iov_len = (len); \
518 	uio.uio_resid += (len); \
519 	iovp++; \
520 	if (++uio.uio_iovcnt >= NIOV) { \
521 		if (BSD__sprint(fp, &uio)) \
522 			goto error; \
523 		iovp = iov; \
524 	} \
525 }
526 #define	PAD(howmany, with) { \
527 	if ((n = (howmany)) > 0) { \
528 		while (n > PADSIZE) { \
529 			PRINT(with, PADSIZE); \
530 			n -= PADSIZE; \
531 		} \
532 		PRINT(with, n); \
533 	} \
534 }
535 #define	FLUSH() { \
536 	if (uio.uio_resid && BSD__sprint(fp, &uio)) \
537 		goto error; \
538 	uio.uio_iovcnt = 0; \
539 	iovp = iov; \
540 }
541 
542 	/*
543 	 * To extend shorts properly, we need both signed and unsigned
544 	 * argument extraction methods.
545 	 */
546 #define	SARG() \
547 	(flags&LONGINT ? va_arg(ap, long) : \
548 	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
549 	    (long)va_arg(ap, int))
550 #define	UARG() \
551 	(flags&LONGINT ? va_arg(ap, u_long) : \
552 	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
553 	    (u_long)va_arg(ap, u_int))
554 
555 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
556 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
557 	    fp->_file >= 0)
558 		return (BSD__sbprintf(fp, fmt0, ap));
559 
560 	fmt = (char *)fmt0;
561 	uio.uio_iov = iovp = iov;
562 	uio.uio_resid = 0;
563 	uio.uio_iovcnt = 0;
564 	ret = 0;
565 
566 	/*
567 	 * Scan the format for conversions (`%' character).
568 	 */
569 	for (;;) {
570 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
571 			/* void */;
572 		if ((n = fmt - cp) != 0) {
573 			PRINT(cp, n);
574 			ret += n;
575 		}
576 		if (ch == '\0')
577 			goto done;
578 		fmt++;		/* skip over '%' */
579 
580 		flags = 0;
581 		dprec = 0;
582 		width = 0;
583 		prec = -1;
584 		sign = '\0';
585 
586 rflag:		ch = *fmt++;
587 reswitch:	switch (ch) {
588 		case ' ':
589 			/*
590 			 * ``If the space and + flags both appear, the space
591 			 * flag will be ignored.''
592 			 *	-- ANSI X3J11
593 			 */
594 			if (!sign)
595 				sign = ' ';
596 			goto rflag;
597 		case '#':
598 			flags |= ALT;
599 			goto rflag;
600 		case '*':
601 			/*
602 			 * ``A negative field width argument is taken as a
603 			 * - flag followed by a positive field width.''
604 			 *	-- ANSI X3J11
605 			 * They don't exclude field widths read from args.
606 			 */
607 			if ((width = va_arg(ap, int)) >= 0)
608 				goto rflag;
609 			width = -width;
610 			/* FALLTHROUGH */
611 		case '-':
612 			flags |= LADJUST;
613 			goto rflag;
614 		case '+':
615 			sign = '+';
616 			goto rflag;
617 		case '.':
618 			if ((ch = *fmt++) == '*') {
619 				n = va_arg(ap, int);
620 				prec = n < 0 ? -1 : n;
621 				goto rflag;
622 			}
623 			n = 0;
624 			while (is_digit(ch)) {
625 				n = 10 * n + to_digit(ch);
626 				ch = *fmt++;
627 			}
628 			prec = n < 0 ? -1 : n;
629 			goto reswitch;
630 		case '0':
631 			/*
632 			 * ``Note that 0 is taken as a flag, not as the
633 			 * beginning of a field width.''
634 			 *	-- ANSI X3J11
635 			 */
636 			flags |= ZEROPAD;
637 			goto rflag;
638 		case '1': case '2': case '3': case '4':
639 		case '5': case '6': case '7': case '8': case '9':
640 			n = 0;
641 			do {
642 				n = 10 * n + to_digit(ch);
643 				ch = *fmt++;
644 			} while (is_digit(ch));
645 			width = n;
646 			goto reswitch;
647 #ifdef FLOATING_POINT
648 		case 'L':
649 			flags |= LONGDBL;
650 			goto rflag;
651 #endif
652 		case 'h':
653 			flags |= SHORTINT;
654 			goto rflag;
655 		case 'l':
656 			flags |= LONGINT;
657 			goto rflag;
658 #ifdef _HAVE_SANE_QUAD_
659 		case 'q':
660 			flags |= QUADINT;
661 			goto rflag;
662 #endif /* _HAVE_SANE_QUAD_ */
663 		case 'c':
664 			*(cp = buf) = va_arg(ap, int);
665 			size = 1;
666 			sign = '\0';
667 			break;
668 		case 'D':
669 			flags |= LONGINT;
670 			/*FALLTHROUGH*/
671 		case 'd':
672 		case 'i':
673 #ifdef _HAVE_SANE_QUAD_
674 			if (flags & QUADINT) {
675 				uqval = va_arg(ap, quad_t);
676 				if ((quad_t)uqval < 0) {
677 					uqval = -uqval;
678 					sign = '-';
679 				}
680 			} else {
681 #else /* _HAVE_SANE_QUAD_ */
682 			{
683 #endif /* _HAVE_SANE_QUAD_ */
684 				ulval = SARG();
685 				if ((long)ulval < 0) {
686 					ulval = -ulval;
687 					sign = '-';
688 				}
689 			}
690 			base = 10;
691 			goto number;
692 #ifdef FLOATING_POINT
693 		case 'e':		/* anomalous precision */
694 		case 'E':
695 			prec = (prec == -1) ?
696 				DEFPREC + 1 : prec + 1;
697 			/* FALLTHROUGH */
698 			goto fp_begin;
699 		case 'f':		/* always print trailing zeroes */
700 			if (prec != 0)
701 				flags |= ALT;
702 		case 'g':
703 		case 'G':
704 			if (prec == -1)
705 				prec = DEFPREC;
706 fp_begin:		_double = va_arg(ap, double);
707 			/* do this before tricky precision changes */
708 			if (isinf(_double)) {
709 				if (_double < 0)
710 					sign = '-';
711 				cp = "Inf";
712 				size = 3;
713 				break;
714 			}
715 			if (isnan(_double)) {
716 				cp = "NaN";
717 				size = 3;
718 				break;
719 			}
720 			flags |= FPT;
721 			cp = cvt(_double, prec, flags, &softsign,
722 				&expt, ch, &ndig);
723 			if (ch == 'g' || ch == 'G') {
724 				if (expt <= -4 || expt > prec)
725 					ch = (ch == 'g') ? 'e' : 'E';
726 				else
727 					ch = 'g';
728 			}
729 			if (ch <= 'e') {	/* 'e' or 'E' fmt */
730 				--expt;
731 				expsize = exponent(expstr, expt, ch);
732 				size = expsize + ndig;
733 				if (ndig > 1 || flags & ALT)
734 					++size;
735 			} else if (ch == 'f') {		/* f fmt */
736 				if (expt > 0) {
737 					size = expt;
738 					if (prec || flags & ALT)
739 						size += prec + 1;
740 				} else	/* "0.X" */
741 					size = prec + 2;
742 			} else if (expt >= ndig) {	/* fixed g fmt */
743 				size = expt;
744 				if (flags & ALT)
745 					++size;
746 			} else
747 				size = ndig + (expt > 0 ?
748 					1 : 2 - expt);
749 
750 			if (softsign)
751 				sign = '-';
752 			break;
753 #endif /* FLOATING_POINT */
754 		case 'n':
755 #ifdef _HAVE_SANE_QUAD_
756 			if (flags & QUADINT)
757 				*va_arg(ap, quad_t *) = ret;
758 			else if (flags & LONGINT)
759 #else /* _HAVE_SANE_QUAD_ */
760 			if (flags & LONGINT)
761 #endif /* _HAVE_SANE_QUAD_ */
762 				*va_arg(ap, long *) = ret;
763 			else if (flags & SHORTINT)
764 				*va_arg(ap, short *) = ret;
765 			else
766 				*va_arg(ap, int *) = ret;
767 			continue;	/* no output */
768 		case 'O':
769 			flags |= LONGINT;
770 			/*FALLTHROUGH*/
771 		case 'o':
772 #ifdef _HAVE_SANE_QUAD_
773 			if (flags & QUADINT)
774 				uqval = va_arg(ap, u_quad_t);
775 			else
776 #endif /* _HAVE_SANE_QUAD_ */
777 				ulval = UARG();
778 			base = 8;
779 			goto nosign;
780 		case 'p':
781 			/*
782 			 * ``The argument shall be a pointer to void.  The
783 			 * value of the pointer is converted to a sequence
784 			 * of printable characters, in an implementation-
785 			 * defined manner.''
786 			 *	-- ANSI X3J11
787 			 */
788 			ulval = (u_long)va_arg(ap, void *);
789 			base = 16;
790 			xdigs = "0123456789abcdef";
791 #ifdef _HAVE_SANE_QUAD_
792 			flags = (flags & ~QUADINT) | HEXPREFIX;
793 #else /* _HAVE_SANE_QUAD_ */
794 			flags = (flags) | HEXPREFIX;
795 #endif /* _HAVE_SANE_QUAD_ */
796 			ch = 'x';
797 			goto nosign;
798 		case 's':
799 			if ((cp = va_arg(ap, char *)) == NULL)
800 				cp = "(null)";
801 			if (prec >= 0) {
802 				/*
803 				 * can't use strlen; can only look for the
804 				 * NUL in the first `prec' characters, and
805 				 * strlen() will go further.
806 				 */
807 				char *p = (char *)memchr(cp, 0, prec);
808 
809 				if (p != NULL) {
810 					size = p - cp;
811 					if (size > prec)
812 						size = prec;
813 				} else
814 					size = prec;
815 			} else
816 				size = strlen(cp);
817 			sign = '\0';
818 			break;
819 		case 'U':
820 			flags |= LONGINT;
821 			/*FALLTHROUGH*/
822 		case 'u':
823 #ifdef _HAVE_SANE_QUAD_
824 			if (flags & QUADINT)
825 				uqval = va_arg(ap, u_quad_t);
826 			else
827 #endif /* _HAVE_SANE_QUAD_ */
828 				ulval = UARG();
829 			base = 10;
830 			goto nosign;
831 		case 'X':
832 			xdigs = "0123456789ABCDEF";
833 			goto hex;
834 		case 'x':
835 			xdigs = "0123456789abcdef";
836 hex:
837 #ifdef _HAVE_SANE_QUAD_
838 			if (flags & QUADINT)
839 				uqval = va_arg(ap, u_quad_t);
840 			else
841 #endif /* _HAVE_SANE_QUAD_ */
842 				ulval = UARG();
843 			base = 16;
844 			/* leading 0x/X only if non-zero */
845 			if (flags & ALT &&
846 #ifdef _HAVE_SANE_QUAD_
847 			    (flags & QUADINT ? uqval != 0 : ulval != 0))
848 #else /* _HAVE_SANE_QUAD_ */
849 			    ulval != 0)
850 #endif /* _HAVE_SANE_QUAD_ */
851 				flags |= HEXPREFIX;
852 
853 			/* unsigned conversions */
854 nosign:			sign = '\0';
855 			/*
856 			 * ``... diouXx conversions ... if a precision is
857 			 * specified, the 0 flag will be ignored.''
858 			 *	-- ANSI X3J11
859 			 */
860 number:			if ((dprec = prec) >= 0)
861 				flags &= ~ZEROPAD;
862 
863 			/*
864 			 * ``The result of converting a zero value with an
865 			 * explicit precision of zero is no characters.''
866 			 *	-- ANSI X3J11
867 			 */
868 			cp = buf + BUF;
869 #ifdef _HAVE_SANE_QUAD_
870 			if (flags & QUADINT) {
871 				if (uqval != 0 || prec != 0)
872 					cp = __uqtoa(uqval, cp, base,
873 					    flags & ALT, xdigs);
874 			} else {
875 #else /* _HAVE_SANE_QUAD_ */
876 			{
877 #endif /* _HAVE_SANE_QUAD_ */
878 				if (ulval != 0 || prec != 0)
879 					cp = BSD__ultoa(ulval, cp, base,
880 					    flags & ALT, xdigs);
881 			}
882 			size = buf + BUF - cp;
883 			break;
884 		default:	/* "%?" prints ?, unless ? is NUL */
885 			if (ch == '\0')
886 				goto done;
887 			/* pretend it was %c with argument ch */
888 			cp = buf;
889 			*cp = ch;
890 			size = 1;
891 			sign = '\0';
892 			break;
893 		}
894 
895 		/*
896 		 * All reasonable formats wind up here.  At this point, `cp'
897 		 * points to a string which (if not flags&LADJUST) should be
898 		 * padded out to `width' places.  If flags&ZEROPAD, it should
899 		 * first be prefixed by any sign or other prefix; otherwise,
900 		 * it should be blank padded before the prefix is emitted.
901 		 * After any left-hand padding and prefixing, emit zeroes
902 		 * required by a decimal [diouxX] precision, then print the
903 		 * string proper, then emit zeroes required by any leftover
904 		 * floating precision; finally, if LADJUST, pad with blanks.
905 		 *
906 		 * Compute actual size, so we know how much to pad.
907 		 * fieldsz excludes decimal prec; realsz includes it.
908 		 */
909 		fieldsz = size;
910 		if (sign)
911 			fieldsz++;
912 		else if (flags & HEXPREFIX)
913 			fieldsz += 2;
914 		realsz = dprec > fieldsz ? dprec : fieldsz;
915 
916 		/* right-adjusting blank padding */
917 		if ((flags & (LADJUST|ZEROPAD)) == 0)
918 			PAD(width - realsz, blanks);
919 
920 		/* prefix */
921 		if (sign) {
922 			PRINT(&sign, 1);
923 		} else if (flags & HEXPREFIX) {
924 			ox[0] = '0';
925 			ox[1] = ch;
926 			PRINT(ox, 2);
927 		}
928 
929 		/* right-adjusting zero padding */
930 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
931 			PAD(width - realsz, zeroes);
932 
933 		/* leading zeroes from decimal precision */
934 		PAD(dprec - fieldsz, zeroes);
935 
936 		/* the string or number proper */
937 #ifdef FLOATING_POINT
938 		if ((flags & FPT) == 0) {
939 			PRINT(cp, size);
940 		} else {	/* glue together f_p fragments */
941 			if (ch >= 'f') {	/* 'f' or 'g' */
942 				if (_double == 0) {
943 				/* kludge for __dtoa irregularity */
944 					if (prec == 0 ||
945 					    (flags & ALT) == 0) {
946 						PRINT("0", 1);
947 					} else {
948 						PRINT("0.", 2);
949 						PAD(ndig - 1, zeroes);
950 					}
951 				} else if (expt <= 0) {
952 					PRINT("0.", 2);
953 					PAD(-expt, zeroes);
954 					PRINT(cp, ndig);
955 				} else if (expt >= ndig) {
956 					PRINT(cp, ndig);
957 					PAD(expt - ndig, zeroes);
958 					if (flags & ALT)
959 						PRINT(".", 1);
960 				} else {
961 					PRINT(cp, expt);
962 					cp += expt;
963 					PRINT(".", 1);
964 					PRINT(cp, ndig-expt);
965 				}
966 			} else {	/* 'e' or 'E' */
967 				if (ndig > 1 || flags & ALT) {
968 					ox[0] = *cp++;
969 					ox[1] = '.';
970 					PRINT(ox, 2);
971 					if (_double || flags & ALT == 0) {
972 						PRINT(cp, ndig-1);
973 					} else	/* 0.[0..] */
974 						/* __dtoa irregularity */
975 						PAD(ndig - 1, zeroes);
976 				} else	/* XeYYY */
977 					PRINT(cp, 1);
978 				PRINT(expstr, expsize);
979 			}
980 		}
981 #else
982 		PRINT(cp, size);
983 #endif
984 		/* left-adjusting padding (always blank) */
985 		if (flags & LADJUST)
986 			PAD(width - realsz, blanks);
987 
988 		/* finally, adjust ret */
989 		ret += width > realsz ? width : realsz;
990 
991 		FLUSH();	/* copy out the I/O vectors */
992 	}
993 done:
994 	FLUSH();
995 error:
996 	return (__sferror(fp) ? EOF : ret);
997 	/* NOTREACHED */
998 }
999 
1000 #ifdef FLOATING_POINT
1001 
1002 extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
1003 
1004 static char *
cvt(value,ndigits,flags,sign,decpt,ch,length)1005 cvt(value, ndigits, flags, sign, decpt, ch, length)
1006 	double value;
1007 	int ndigits, flags, *decpt, ch, *length;
1008 	char *sign;
1009 {
1010 	int mode, dsgn;
1011 	char *digits, *bp, *rve;
1012 
1013 	if (ch == 'f')
1014 		mode = 3;
1015 	else {
1016 		mode = 2;
1017 	}
1018 	if (value < 0) {
1019 		value = -value;
1020 		*sign = '-';
1021 	} else
1022 		*sign = '\000';
1023 	digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
1024 	if (flags & ALT) {	/* Print trailing zeros */
1025 		bp = digits + ndigits;
1026 		if (ch == 'f') {
1027 			if (*digits == '0' && value)
1028 				*decpt = -ndigits + 1;
1029 			bp += *decpt;
1030 		}
1031 		if (value == 0)	/* kludge for __dtoa irregularity */
1032 			rve = bp;
1033 		while (rve < bp)
1034 			*rve++ = '0';
1035 	}
1036 	*length = rve - digits;
1037 	return (digits);
1038 }
1039 
1040 static int
exponent(p0,exp,fmtch)1041 exponent(p0, exp, fmtch)
1042 	char *p0;
1043 	int exp, fmtch;
1044 {
1045 	register char *p, *t;
1046 	char expbuf[MAXEXP];
1047 
1048 	p = p0;
1049 	*p++ = fmtch;
1050 	if (exp < 0) {
1051 		exp = -exp;
1052 		*p++ = '-';
1053 	}
1054 	else
1055 		*p++ = '+';
1056 	t = expbuf + MAXEXP;
1057 	if (exp > 9) {
1058 		do {
1059 			*--t = to_char(exp % 10);
1060 		} while ((exp /= 10) > 9);
1061 		*--t = to_char(exp);
1062 		for (; t < expbuf + MAXEXP; *p++ = *t++);
1063 	}
1064 	else {
1065 		*p++ = '0';
1066 		*p++ = to_char(exp);
1067 	}
1068 	return (p - p0);
1069 }
1070 #endif /* FLOATING_POINT */
1071 
1072 int
vsnprintf(str,n,fmt,ap)1073 vsnprintf(str, n, fmt, ap)
1074 	char *str;
1075 	size_t n;
1076 	const char *fmt;
1077 	_BSD_VA_LIST_ ap;
1078 {
1079 	int ret;
1080 	FILE f;
1081 
1082 	if ((int)n < 1)
1083 		return (EOF);
1084 	f._flags = __SWR | __SSTR;
1085 	f._bf._base = f._p = (unsigned char *)str;
1086 	f._bf._size = f._w = n - 1;
1087 	ret = BSD_vfprintf(&f, fmt, ap);
1088 	*f._p = 0;
1089 	return (ret);
1090 }
1091 
1092 #if defined(LIBC_SCCS) && !defined(lint)
1093 static char sccsid[] = "@(#)snprintf.c	8.1 (Berkeley) 6/4/93";
1094 #endif /* LIBC_SCCS and not lint */
1095 
1096 #if defined(__STDC__)
1097 # include <stdarg.h>
1098 #else
1099 # include <varargs.h>
1100 #endif
1101 
1102 int
1103 #if defined(__STDC__)
snprintf(char * str,size_t n,char const * fmt,...)1104 snprintf(char *str, size_t n, char const *fmt, ...)
1105 #else
1106 snprintf(str, n, fmt, va_alist)
1107 char *str, *fmt;
1108 size_t n;
1109 va_dcl
1110 #endif
1111 {
1112 	int ret;
1113 	va_list ap;
1114 	FILE f;
1115 
1116 	if ((int)n < 1)
1117 		return (EOF);
1118 
1119 #if defined(__STDC__)
1120 	va_start(ap, fmt);
1121 #else
1122 	va_start(ap);
1123 #endif
1124 	f._flags = __SWR | __SSTR;
1125 	f._bf._base = f._p = (unsigned char *)str;
1126 	f._bf._size = f._w = n - 1;
1127 	ret = BSD_vfprintf(&f, fmt, ap);
1128 	*f._p = 0;
1129 	va_end(ap);
1130 	return (ret);
1131 }
1132