diff options
Diffstat (limited to 'lib/libc/stdio/vfprintf.c')
-rw-r--r-- | lib/libc/stdio/vfprintf.c | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 5e5a9b5e31c1..2dc8d9022179 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -37,10 +37,6 @@ * SUCH DAMAGE. */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include <sys/cdefs.h> /* * Actual printf innards. * @@ -72,7 +68,8 @@ static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; #include "printflocal.h" static int __sprint(FILE *, struct __suio *, locale_t); -static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0) +static int __sbprintf(FILE *, locale_t, int, const char *, va_list) + __printflike(4, 0) __noinline; static char *__wcsconv(wchar_t *, int); @@ -173,7 +170,7 @@ __sprint(FILE *fp, struct __suio *uio, locale_t locale) * worries about ungetc buffers and so forth. */ static int -__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap) +__sbprintf(FILE *fp, locale_t locale, int serrno, const char *fmt, va_list ap) { int ret; FILE fake = FAKE_FILE; @@ -197,7 +194,7 @@ __sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap) fake._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ - ret = __vfprintf(&fake, locale, fmt, ap); + ret = __vfprintf(&fake, locale, serrno, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = EOF; if (fake._flags & __SERR) @@ -269,8 +266,9 @@ __wcsconv(wchar_t *wcsarg, int prec) */ int vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, - va_list ap) + va_list ap) { + int serrno = errno; int ret; FIX_LOCALE(locale); @@ -278,9 +276,9 @@ vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) - ret = __sbprintf(fp, locale, fmt0, ap); + ret = __sbprintf(fp, locale, serrno, fmt0, ap); else - ret = __vfprintf(fp, locale, fmt0, ap); + ret = __vfprintf(fp, locale, serrno, fmt0, ap); FUNLOCKFILE_CANCELSAFE(); return (ret); } @@ -293,19 +291,15 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) /* * The size of the buffer we use as scratch space for integer * conversions, among other things. We need enough space to - * write a uintmax_t in octal (plus one byte). + * write a uintmax_t in binary. */ -#if UINTMAX_MAX <= UINT64_MAX -#define BUF 32 -#else -#error "BUF must be large enough to format a uintmax_t" -#endif +#define BUF (sizeof(uintmax_t) * CHAR_BIT) /* * Non-MT-safe version */ int -__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) +__vfprintf(FILE *fp, locale_t locale, int serrno, const char *fmt0, va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ @@ -315,7 +309,8 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ - int saved_errno; + int error; + char errnomsg[NL_TEXTMAX]; char sign; /* sign prefix (' ', '+', '-', or \0) */ struct grouping_state gs; /* thousands' grouping info */ @@ -451,8 +446,6 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) val = GETARG (int); \ } - if (__use_xprintf == 0 && getenv("USE_XPRINTF")) - __use_xprintf = 1; if (__use_xprintf > 0) return (__xvprintf(fp, fmt0, ap)); @@ -465,7 +458,6 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) savserr = fp->_flags & __SERR; fp->_flags &= ~__SERR; - saved_errno = errno; convbuf = NULL; fmt = (char *)fmt0; argtable = NULL; @@ -610,6 +602,49 @@ reswitch: switch (ch) { case 't': flags |= PTRDIFFT; goto rflag; + case 'w': + /* + * Fixed-width integer types. On all platforms we + * support, int8_t is equivalent to char, int16_t + * is equivalent to short, int32_t is equivalent + * to int, int64_t is equivalent to long long int. + * Furthermore, int_fast8_t, int_fast16_t and + * int_fast32_t are equivalent to int, and + * int_fast64_t is equivalent to long long int. + */ + flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT); + if (fmt[0] == 'f') { + flags |= FASTINT; + fmt++; + } else { + flags &= ~FASTINT; + } + if (fmt[0] == '8') { + if (!(flags & FASTINT)) + flags |= CHARINT; + else + /* no flag set = 32 */ ; + fmt += 1; + } else if (fmt[0] == '1' && fmt[1] == '6') { + if (!(flags & FASTINT)) + flags |= SHORTINT; + else + /* no flag set = 32 */ ; + fmt += 2; + } else if (fmt[0] == '3' && fmt[1] == '2') { + /* no flag set = 32 */ ; + fmt += 2; + } else if (fmt[0] == '6' && fmt[1] == '4') { + flags |= LLONGINT; + fmt += 2; + } else { + if (flags & FASTINT) { + flags &= ~FASTINT; + fmt--; + } + goto invalid; + } + goto rflag; case 'z': flags |= SIZET; goto rflag; @@ -790,7 +825,9 @@ fp_common: break; #endif /* !NO_FLOATING_POINT */ case 'm': - cp = strerror(saved_errno); + error = __strerror_rl(serrno, errnomsg, + sizeof(errnomsg), locale); + cp = error == 0 ? errnomsg : "<strerror failure>"; size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); sign = '\0'; break; @@ -932,6 +969,7 @@ number: if ((dprec = prec) >= 0) default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') goto done; +invalid: /* pretend it was %c with argument ch */ cp = buf; *cp = ch; |