#include "stdio_impl.h"
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <inttypes.h>
+#include <math.h>
+#include <float.h>
/* Some useful macros */
#define MAX(a,b) ((a)>(b) ? (a) : (b))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
-#define CONCAT2(x,y) x ## y
-#define CONCAT(x,y) CONCAT2(x,y)
/* Convenient bit representation for modifier flags, which all fall
* within 31 codepoints of the space character. */
static void out(FILE *f, const char *s, size_t l)
{
- __fwritex((void *)s, l, f);
+ if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
}
static void pad(FILE *f, char c, int w, int l, int fl)
return s;
}
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+
static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
{
- uint32_t big[(LDBL_MAX_EXP+LDBL_MANT_DIG)/9+1];
+ uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
uint32_t *a, *d, *r, *z;
int e2=0, e, i, j, l;
char buf[9+LDBL_MANT_DIG/4], *s;
char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
pl=1;
- if (y<0 || 1/y<0) {
+ if (signbit(y)) {
y=-y;
} else if (fl & MARK_POS) {
prefix+=3;
if (!isfinite(y)) {
char *s = (t&32)?"inf":"INF";
- if (y!=y) s=(t&32)?"nan":"NAN", pl=0;
+ if (y!=y) s=(t&32)?"nan":"NAN";
pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
out(f, prefix, pl);
out(f, s, 3);
*d = x % 1000000000;
carry = x / 1000000000;
}
- if (!z[-1] && z>a) z--;
if (carry) *--a = carry;
+ while (z>a && !z[-1]) z--;
e2-=sh;
}
while (e2<0) {
uint32_t carry=0, *b;
- int sh=MIN(9,-e2);
+ int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9;
for (d=a; d<z; d++) {
uint32_t rm = *d & (1<<sh)-1;
*d = (*d>>sh) + carry;
if (carry) *z++ = carry;
/* Avoid (slow!) computation past requested precision */
b = (t|32)=='f' ? r : a;
- if (z-b > 2+p/9) z = b+2+p/9;
+ if (z-b > need) z = b+need;
e2+=sh;
}
x = *d % i;
/* Are there any significant digits past j? */
if (x || d+1!=z) {
- long double round = CONCAT(0x1p,LDBL_MANT_DIG);
+ long double round = 2/LDBL_EPSILON;
long double small;
if (*d/i & 1) round += 2;
if (x<i/2) small=0x0.8p0;
*d = *d + i;
while (*d > 999999999) {
*d--=0;
+ if (d<a) *--a=0;
(*d)++;
}
- if (d<a) a=d;
for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
}
}
if (z>d+1) z=d+1;
- for (; !z[-1] && z>a; z--);
}
+ for (; z>a && !z[-1]; z--);
if ((t|32)=='g') {
if (!p) p++;
/* Check validity of argument type (nl/normal) */
if (st==NOARG) {
if (argpos>=0) return -1;
- else if (!f) continue;
} else {
if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
else if (f) pop_arg(&arg, st, ap);
if (0) {
case 'o':
a = fmt_o(arg.i, z);
- if ((fl&ALT_FORM) && arg.i) prefix+=5, pl=1;
+ if ((fl&ALT_FORM) && p<z-a+1) prefix+=5, pl=1;
} if (0) {
case 'd': case 'i':
pl=1;
return 1;
}
-int vfprintf(FILE *f, const char *fmt, va_list ap)
+int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
{
va_list ap2;
int nl_type[NL_ARGMAX+1] = {0};
union arg nl_arg[NL_ARGMAX+1];
unsigned char internal_buf[80], *saved_buf = 0;
+ int olderr;
int ret;
+ /* the copy allows passing va_list* even if va_list is an array */
va_copy(ap2, ap);
- if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1;
+ if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
+ va_end(ap2);
+ return -1;
+ }
FLOCK(f);
+ olderr = f->flags & F_ERR;
+ if (f->mode < 1) f->flags &= ~F_ERR;
if (!f->buf_size) {
saved_buf = f->buf;
f->wpos = f->wbase = f->buf = internal_buf;
f->buf_size = 0;
f->wpos = f->wbase = f->wend = 0;
}
+ if (f->flags & F_ERR) ret = -1;
+ f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
return ret;