2
* Copyright (c) 1990 The Regents of the University of California.
3
* Copyright (c) 1993, 1994 Chris Provenzano.
6
* This code is derived from software contributed to Berkeley by
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
* 3. All advertising materials mentioning features or use of this software
18
* must display the following acknowledgement:
19
* This product includes software developed by the University of
20
* California, Berkeley and its contributors.
21
* 4. Neither the name of the University nor the names of its contributors
22
* may be used to endorse or promote products derived from this software
23
* without specific prior written permission.
25
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
#if defined(LIBC_SCCS) && !defined(lint)
39
/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
40
static char *rcsid = "$Id$";
41
#endif /* LIBC_SCCS and not lint */
44
* Actual printf innards.
46
* This code is large and complicated...
50
#include <sys/types.h>
60
/* Define FLOATING_POINT to get floating point. */
61
#define FLOATING_POINT
64
* Flush out all the vectors defined by the given uio,
65
* then reset it so that it can be reused.
70
register struct __suio *uio;
74
if (uio->uio_resid == 0) {
78
err = __sfvwrite(fp, uio);
85
* Helper function for `fprintf to unbuffered unix file': creates a
86
* temporary buffer. We only work on write-only files; this avoids
87
* worries about ungetc buffers and so forth.
90
__sbprintf(fp, fmt, ap)
95
unsigned char buf[BUFSIZ];
99
/* copy the important variables */
100
fake._flags = fp->_flags & ~__SNBF;
101
fake._file = fp->_file;
103
/* set up the buffer */
104
fake._bf._base = fake._p = buf;
105
fake._bf._size = fake._w = sizeof(buf);
106
fake._lbfsize = 0; /* not actually used, but Just In Case */
108
/* do the work, then copy any error status */
109
ret = vfprintf(&fake, fmt, ap);
110
if (ret >= 0 && fflush(&fake))
112
if (fake._flags & __SERR)
113
fp->_flags |= __SERR;
118
#ifdef FLOATING_POINT
123
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
126
static char *cvt __P_((double, int, int, char *, int *, int, int *));
127
static int exponent __P_((char *, int, int));
129
#else /* no FLOATING_POINT */
133
#endif /* FLOATING_POINT */
137
* Macros for converting digits to letters and vice versa
139
#define to_digit(c) ((c) - '0')
140
#define is_digit(c) ((unsigned)to_digit(c) <= 9)
141
#define to_char(n) ((n) + '0')
144
* Flags used during conversion.
146
#define ALT 0x001 /* alternate form */
147
#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
148
#define LADJUST 0x004 /* left adjustment */
149
#define LONGDBL 0x008 /* long double; unimplemented */
150
#define LONGINT 0x010 /* long integer */
151
#define QUADINT 0x020 /* quad integer */
152
#define SHORTINT 0x040 /* short integer */
153
#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
154
#define FPT 0x100 /* Floating point number */
156
vfprintf(fp, fmt0, ap)
161
register char *fmt; /* format string */
162
register int ch; /* character from fmt */
163
register int n; /* handy integer (short term usage) */
164
register char *cp; /* handy char pointer (short term usage) */
165
register struct __siov *iovp;/* for PRINT macro */
166
register int flags; /* flags as above */
167
int ret; /* return value accumulator */
168
int width; /* width from format (%8d), or 0 */
169
int prec; /* precision from format (%.3d), or -1 */
170
char sign; /* sign prefix (' ', '+', '-', or \0) */
171
#ifdef FLOATING_POINT
172
char softsign; /* temporary negative sign for floats */
173
double _double; /* double precision arguments %[eEfgG] */
174
int expt; /* integer value of exponent */
175
int expsize; /* character count for expstr */
176
int ndig; /* actual number of digits returned by cvt */
177
char expstr[7]; /* buffer for exponent string */
180
#if defined (__alpha) && !defined(_GNUC_)
182
#define u_quad_t unsigned long
183
#else /* gcc has builtin quad type (long long) SOS */
184
#define quad_t long long
185
#define u_quad_t unsigned long long
188
u_quad_t _uquad; /* integer arguments %[diouxX] */
189
enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
190
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
191
int fieldsz; /* field size expanded by sign, etc */
192
int realsz; /* field size expanded by dprec */
193
int size; /* size of converted field or string */
194
char *xdigs; /* digits for [xX] conversion */
196
struct __suio uio; /* output information: summary */
197
struct __siov iov[NIOV];/* ... and individual io vectors */
198
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
199
char ox[2]; /* space for 0x hex-prefix */
202
* Choose PADSIZE to trade efficiency vs. size. If larger printf
203
* fields occur frequently, increase PADSIZE and make the initialisers
206
#define PADSIZE 16 /* pad chunk size */
207
static char blanks[PADSIZE] =
208
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
209
static char zeroes[PADSIZE] =
210
{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
213
* BEWARE, these `goto error' on error, and PAD uses `n'.
215
#define PRINT(ptr, len) { \
216
iovp->iov_base = (ptr); \
217
iovp->iov_len = (len); \
218
uio.uio_resid += (len); \
220
if (++uio.uio_iovcnt >= NIOV) { \
221
if (__sprint(fp, &uio)) \
226
#define PAD(howmany, with) { \
227
if ((n = (howmany)) > 0) { \
228
while (n > PADSIZE) { \
229
PRINT(with, PADSIZE); \
236
if (uio.uio_resid && __sprint(fp, &uio)) \
238
uio.uio_iovcnt = 0; \
243
* To extend shorts properly, we need both signed and unsigned
244
* argument extraction methods.
247
(flags&QUADINT ? va_arg(ap, quad_t) : \
248
flags&LONGINT ? va_arg(ap, long) : \
249
flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
250
(long)va_arg(ap, int))
252
(flags&QUADINT ? va_arg(ap, u_quad_t) : \
253
flags&LONGINT ? va_arg(ap, u_long) : \
254
flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
255
(u_long)va_arg(ap, u_int))
259
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
263
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
264
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
266
ret = (__sbprintf(fp, fmt0, ap));
272
uio.uio_iov = iovp = iov;
278
* Scan the format for conversions (`%' character).
281
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
283
if ((n = fmt - cp) != 0) {
289
fmt++; /* skip over '%' */
298
reswitch: switch (ch) {
301
* ``If the space and + flags both appear, the space
302
* flag will be ignored.''
313
* ``A negative field width argument is taken as a
314
* - flag followed by a positive field width.''
316
* They don't exclude field widths read from args.
318
if ((width = va_arg(ap, int)) >= 0)
329
if ((ch = *fmt++) == '*') {
331
prec = n < 0 ? -1 : n;
335
while (is_digit(ch)) {
336
n = 10 * n + to_digit(ch);
339
prec = n < 0 ? -1 : n;
343
* ``Note that 0 is taken as a flag, not as the
344
* beginning of a field width.''
349
case '1': case '2': case '3': case '4':
350
case '5': case '6': case '7': case '8': case '9':
353
n = 10 * n + to_digit(ch);
355
} while (is_digit(ch));
358
#ifdef FLOATING_POINT
373
*(cp = buf) = va_arg(ap, int);
383
if ((quad_t)_uquad < 0) {
389
#ifdef FLOATING_POINT
397
} else if ((ch == 'g' || ch == 'G') && prec == 0) {
401
if (flags & LONGDBL) {
402
_double = (double) va_arg(ap, long double);
404
_double = va_arg(ap, double);
407
/* do this before tricky precision changes */
408
/* if (isinf(_double)) {
415
/* if (isnan(_double)) {
422
cp = cvt(_double, prec, flags, &softsign,
424
if (ch == 'g' || ch == 'G') {
425
if (expt <= -4 || expt > prec)
426
ch = (ch == 'g') ? 'e' : 'E';
430
if (ch <= 'e') { /* 'e' or 'E' fmt */
432
expsize = exponent(expstr, expt, ch);
433
size = expsize + ndig;
434
if (ndig > 1 || flags & ALT)
436
} else if (ch == 'f') { /* f fmt */
439
if (prec || flags & ALT)
443
} else if (expt >= ndig) { /* fixed g fmt */
448
size = ndig + (expt > 0 ?
454
#endif /* FLOATING_POINT */
457
*va_arg(ap, quad_t *) = ret;
458
else if (flags & LONGINT)
459
*va_arg(ap, long *) = ret;
460
else if (flags & SHORTINT)
461
*va_arg(ap, short *) = ret;
463
*va_arg(ap, int *) = ret;
464
continue; /* no output */
474
* ``The argument shall be a pointer to void. The
475
* value of the pointer is converted to a sequence
476
* of printable characters, in an implementation-
481
_uquad = (u_quad_t)(size_t)va_arg(ap, void *);
483
xdigs = "0123456789abcdef";
488
if ((cp = va_arg(ap, char *)) == NULL)
492
* can't use strlen; can only look for the
493
* NUL in the first `prec' characters, and
494
* strlen() will go further.
496
char *p = memchr(cp, 0, prec);
516
xdigs = "0123456789ABCDEF";
519
xdigs = "0123456789abcdef";
520
hex: _uquad = UARG();
522
/* leading 0x/X only if non-zero */
523
if (flags & ALT && _uquad != 0)
526
/* unsigned conversions */
529
* ``... diouXx conversions ... if a precision is
530
* specified, the 0 flag will be ignored.''
533
number: if ((dprec = prec) >= 0)
537
* ``The result of converting a zero value with an
538
* explicit precision of zero is no characters.''
542
if (_uquad != 0 || prec != 0) {
544
* Unsigned mod is hard, and unsigned mod
545
* by a constant is easier than that by
546
* a variable; hence this switch.
551
*--cp = to_char(_uquad & 7);
554
/* handle octal leading 0 */
555
if (flags & ALT && *cp != '0')
560
/* many numbers are 1 digit */
561
while (_uquad >= 10) {
562
*--cp = to_char(_uquad % 10);
565
*--cp = to_char(_uquad);
570
*--cp = xdigs[_uquad & 15];
576
cp = "bug in vfprintf: bad base";
581
size = buf + BUF - cp;
584
default: /* "%?" prints ?, unless ? is NUL */
587
/* pretend it was %c with argument ch */
596
* All reasonable formats wind up here. At this point, `cp'
597
* points to a string which (if not flags&LADJUST) should be
598
* padded out to `width' places. If flags&ZEROPAD, it should
599
* first be prefixed by any sign or other prefix; otherwise,
600
* it should be blank padded before the prefix is emitted.
601
* After any left-hand padding and prefixing, emit zeroes
602
* required by a decimal [diouxX] precision, then print the
603
* string proper, then emit zeroes required by any leftover
604
* floating precision; finally, if LADJUST, pad with blanks.
606
* Compute actual size, so we know how much to pad.
607
* fieldsz excludes decimal prec; realsz includes it.
612
else if (flags & HEXPREFIX)
614
realsz = dprec > fieldsz ? dprec : fieldsz;
616
/* right-adjusting blank padding */
617
if ((flags & (LADJUST|ZEROPAD)) == 0)
618
PAD(width - realsz, blanks);
623
} else if (flags & HEXPREFIX) {
629
/* right-adjusting zero padding */
630
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
631
PAD(width - realsz, zeroes);
633
/* leading zeroes from decimal precision */
634
PAD(dprec - fieldsz, zeroes);
636
/* the string or number proper */
637
#ifdef FLOATING_POINT
638
if ((flags & FPT) == 0) {
640
} else { /* glue together f_p fragments */
641
if (ch >= 'f') { /* 'f' or 'g' */
643
/* kludge for __dtoa irregularity */
644
if (expt >= ndig && (flags & ALT) == 0) {
648
PAD(ndig - 1, zeroes);
650
} else if (expt <= 0) {
654
} else if (expt >= ndig) {
656
PAD(expt - ndig, zeroes);
663
PRINT(cp, ndig-expt);
665
} else { /* 'e' or 'E' */
666
if (ndig > 1 || flags & ALT) {
670
if (_double || flags & ALT == 0) {
673
/* __dtoa irregularity */
674
PAD(ndig - 1, zeroes);
677
PRINT(expstr, expsize);
683
/* left-adjusting padding (always blank) */
685
PAD(width - realsz, blanks);
687
/* finally, adjust ret */
688
ret += width > realsz ? width : realsz;
690
FLUSH(); /* copy out the I/O vectors */
701
#ifdef FLOATING_POINT
703
extern char *__dtoa __P_((double, int, int, int *, int *, char **));
706
cvt(value, ndigits, flags, sign, decpt, ch, length)
708
int ndigits, flags, *decpt, ch, *length;
712
char *digits, *bp, *rve;
715
mode = 3; /* ndigits after the decimal point */
717
/* To obtain ndigits after the decimal point for the 'e'
718
* and 'E' formats, round to ndigits + 1 significant
721
if (ch == 'e' || ch == 'E') {
724
mode = 2; /* ndigits significant digits */
732
/* #if !defined(__alpha__) && !defined(hpux) */
733
#ifndef THIS_IS_NEVER_DEFINED
734
digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
736
{ char *ecvt(double,int,int*,int*);
738
digits = ecvt(value, ndigits, decpt, &dsgn);
739
rve = (digits + (int)strlen(digits));
742
if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
743
bp = digits + ndigits;
745
if (*digits == '0' && value)
746
*decpt = -ndigits + 1;
749
if (value == 0) /* kludge for __dtoa irregularity */
754
*length = rve - digits;
759
exponent(p0, exp, fmtch)
763
register char *p, *t;
777
*--t = to_char(exp % 10);
778
} while ((exp /= 10) > 9);
780
for (; t < expbuf + MAXEXP; *p++ = *t++);
788
#endif /* FLOATING_POINT */