f73e0a2f1b3afb13ffd455508b514cf2eea0962f
* Copyright (c) 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)vfprintf.c 5.9 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
#define PUTC(ch, fd) {++cnt; putc(ch, fd);}
r = argsize&LONGINT ? va_arg(argp, long) : \
argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
register u_long reg_ulong
;
register char *digs
, *bp
, *t
, padc
;
char argsize
, *_cvt(), buf
[MAXBUF
];
int cnt
, n
, ladjust
, width
, prec
, size
;
digs
= "0123456789abcdef";
for (cnt
= 0; *fmt
; ++fmt
) {
alternate
= ladjust
= width
= 0;
argsize
= printsign
= '\0';
* ``A negative field width argument is taken as a
* - flag followed by a positive field width.''
* They don't exclude field widths read from args.
if ((width
= va_arg(argp
, int)) >= 0)
prec
= va_arg(argp
, int);
else if (isdigit(*fmt
)) {
prec
= 10 * prec
+ *fmt
- '0';
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width
= 10 * width
+ *fmt
- '0';
_double
= va_arg(argp
, double);
bp
= _cvt(_double
, prec
, buf
, buf
+ sizeof(buf
), *fmt
);
if (size
< width
&& !ladjust
)
} while (--width
> size
);
for (t
= buf
; t
< bp
; ++t
)
for (; width
> size
; --width
)
*(va_arg(argp
, int *)) = cnt
;
if (!reg_ulong
|| !alternate
)
bp
= buf
+ sizeof(buf
) - 1;
*bp
-- = digs
[reg_ulong
% base
];
size
= &buf
[sizeof(buf
) - 1] - bp
;
if (size
< --width
&& !ladjust
)
} while (--width
> size
);
if (!(bp
= va_arg(argp
, char *)))
if (width
> 0 && !ladjust
) {
for (n
= 0; *bp
&& (prec
< 0 || n
< prec
);
if (++n
> prec
&& prec
>= 0)
if (n
< width
&& ladjust
)
digs
= "0123456789ABCDEF";
if (alternate
&& reg_ulong
) {
num1
: bp
= buf
+ sizeof(buf
) - 1;
*bp
-- = digs
[reg_ulong
% base
];
size
= &buf
[sizeof(buf
) - 1] - bp
;
for (; size
< prec
; *bp
-- = '0', ++size
);
if (size
< width
&& !ladjust
)
} while (--width
> size
);
num2
: while (++bp
!= &buf
[MAXBUF
])
for (; width
> size
; --width
)
digs
= "0123456789abcdef";
case '\0': /* "%?" prints ?, unless ? is NULL */
return(ferror(fp
) ? -1 : cnt
);
return(ferror(fp
) ? -1 : cnt
);
_cvt(number
, prec
, startp
, endp
, fmtch
)
char *startp
, *endp
, fmtch
;
register int expcnt
, format
;
double fract
, integer
, tmp
, modf();
if (prec
== -1) /* set default precision */
if (number
< 0) { /* set sign */
* if the alternate flag is set, or, at least one digit of precision
* was requested, add a decimal point, unless it's the g/G format
* in which case we require two digits of precision, since it counts
decpt
= alternate
|| prec
> 1 || !(format
&GFORMAT
) && prec
;
fract
= modf(number
, &integer
);
/* get integer part of number; count decimal places */
for (; integer
; ++expcnt
) {
tmp
= modf(integer
/ 10, &integer
);
*p
-- = (int)((tmp
+ .03) * 10) + '0';
/* copy, in reverse order, to start of buffer */
* if the format is g/G, and the resulting exponent will be
* greater than the precision, use e/E format. If e/E format,
* put in a decimal point as needed, and decrement precision
* count for each digit after the decimal point.
if (format
&GFORMAT
&& expcnt
- 1 > prec
|| format
&EFORMAT
) {
/* first digit is precision for g/G format */
for (; ++p
< endp
&& prec
; --prec
, *p2
++ = *p
);
/* precision ran out; round number */
for (savep
= p2
--;; *p2
-- = '0') {
* g/G in f format; if run out of precision, replace digits
* with zeroes, note, have to round first, otherwise lose
else if (format
&GFORMAT
) {
for (; ++p
< endp
&& prec
; --prec
, *p2
++ = *p
);
/* precision ran out; round and then add zeroes */
for (savep
= p2
--; ++*p2
> '9';
for (; ++p
< endp
; *p2
++ = *p
);
* it's unclear from the ANSI X3J11 spec if the g/G format should
* just result in an empty string, because it's supposed to remove
* trailing zeroes. That seems counter-intuitive, so here it does
* what f and e/E do; if no fraction, the number was zero, and if
* no precision can't show anything after the decimal point.
else if (!fract
|| !prec
) {
* if the format is g/G, and the resulting exponent will be less than
* -4 use e/E format. If e/E format, compute exponent value.
else if (format
&GFORMAT
&& fract
< .0001 || format
&EFORMAT
) {
for (p
= startp
; fract
;) {
fract
= modf(fract
* 10, &tmp
);
/* g/G format, decrement precision for first digit */
if (format
&GFORMAT
&& prec
)
/* add decimal after first non-zero digit */
* f format or g/G printed as f format; don't worry about decimal
* point, if g/G format doesn't need it, will get stripped later.
/* finish out requested precision from fractional value */
fract
= modf(fract
* 10, &tmp
);
* if any fractional value left, "round" it back up to the beginning
* of the number, fixing the exponent as necessary, and avoiding the
(void)modf(fract
* 10, &tmp
);
for (savep
= p
--;; *p
-- = '0') {
* if a g/G format and not alternate flag, lose trailing zeroes,
* if e/E or g/G format, and last char is decimal point, lose it.
for (; p
[-1] == '0'; --p
);
if (format
&(GFORMAT
|EFORMAT
) && p
[-1] == '.')
/* if an e/E format, add exponent */
*p
++ = expcnt
/ 10 + '0';
*p
++ = expcnt
% 10 + '0';