master
  1#include "stdio_impl.h"
  2#include <errno.h>
  3#include <ctype.h>
  4#include <limits.h>
  5#include <string.h>
  6#include <stdarg.h>
  7#include <stddef.h>
  8#include <stdlib.h>
  9#include <wchar.h>
 10#include <inttypes.h>
 11#include <math.h>
 12#include <float.h>
 13#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
 14#else
 15#include "printscan.h"
 16#endif
 17
 18/* Some useful macros */
 19
 20#define MAX(a,b) ((a)>(b) ? (a) : (b))
 21#define MIN(a,b) ((a)<(b) ? (a) : (b))
 22
 23/* Convenient bit representation for modifier flags, which all fall
 24 * within 31 codepoints of the space character. */
 25
 26#define ALT_FORM   (1U<<'#'-' ')
 27#define ZERO_PAD   (1U<<'0'-' ')
 28#define LEFT_ADJ   (1U<<'-'-' ')
 29#define PAD_POS    (1U<<' '-' ')
 30#define MARK_POS   (1U<<'+'-' ')
 31#define GROUPED    (1U<<'\''-' ')
 32
 33#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
 34
 35/* State machine to accept length modifiers + conversion specifiers.
 36 * Result is 0 on failure, or an argument type to pop on success. */
 37
 38enum {
 39	BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
 40	ZTPRE, JPRE,
 41	STOP,
 42	PTR, INT, UINT, ULLONG,
 43	LONG, ULONG,
 44	SHORT, USHORT, CHAR, UCHAR,
 45	LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
 46	DBL, LDBL,
 47	NOARG,
 48	MAXSTATE
 49};
 50
 51#define S(x) [(x)-'A']
 52
 53static const unsigned char states[]['z'-'A'+1] = {
 54	{ /* 0: bare types */
 55		S('d') = INT, S('i') = INT,
 56		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
 57		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 58		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
 59		S('c') = INT, S('C') = UINT,
 60		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
 61		S('m') = NOARG,
 62		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
 63		S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
 64	}, { /* 1: l-prefixed */
 65		S('d') = LONG, S('i') = LONG,
 66		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
 67		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 68		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
 69		S('c') = UINT, S('s') = PTR, S('n') = PTR,
 70		S('l') = LLPRE,
 71	}, { /* 2: ll-prefixed */
 72		S('d') = LLONG, S('i') = LLONG,
 73		S('o') = ULLONG, S('u') = ULLONG,
 74		S('x') = ULLONG, S('X') = ULLONG,
 75		S('n') = PTR,
 76	}, { /* 3: h-prefixed */
 77		S('d') = SHORT, S('i') = SHORT,
 78		S('o') = USHORT, S('u') = USHORT,
 79		S('x') = USHORT, S('X') = USHORT,
 80		S('n') = PTR,
 81		S('h') = HHPRE,
 82	}, { /* 4: hh-prefixed */
 83		S('d') = CHAR, S('i') = CHAR,
 84		S('o') = UCHAR, S('u') = UCHAR,
 85		S('x') = UCHAR, S('X') = UCHAR,
 86		S('n') = PTR,
 87	}, { /* 5: L-prefixed */
 88		S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
 89		S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
 90		S('n') = PTR,
 91	}, { /* 6: z- or t-prefixed (assumed to be same size) */
 92		S('d') = PDIFF, S('i') = PDIFF,
 93		S('o') = SIZET, S('u') = SIZET,
 94		S('x') = SIZET, S('X') = SIZET,
 95		S('n') = PTR,
 96	}, { /* 7: j-prefixed */
 97		S('d') = IMAX, S('i') = IMAX,
 98		S('o') = UMAX, S('u') = UMAX,
 99		S('x') = UMAX, S('X') = UMAX,
100		S('n') = PTR,
101	}
102};
103
104#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
105
106union arg
107{
108	uintmax_t i;
109#if !defined(__wasilibc_printscan_no_floating_point)
110#if defined(__wasilibc_printscan_no_long_double)
111	long_double f;
112#else
113	long double f;
114#endif
115#endif
116	void *p;
117};
118
119static void pop_arg(union arg *arg, int type, va_list *ap)
120{
121	switch (type) {
122	       case PTR:	arg->p = va_arg(*ap, void *);
123	break; case INT:	arg->i = va_arg(*ap, int);
124	break; case UINT:	arg->i = va_arg(*ap, unsigned int);
125	break; case LONG:	arg->i = va_arg(*ap, long);
126	break; case ULONG:	arg->i = va_arg(*ap, unsigned long);
127	break; case ULLONG:	arg->i = va_arg(*ap, unsigned long long);
128	break; case SHORT:	arg->i = (short)va_arg(*ap, int);
129	break; case USHORT:	arg->i = (unsigned short)va_arg(*ap, int);
130	break; case CHAR:	arg->i = (signed char)va_arg(*ap, int);
131	break; case UCHAR:	arg->i = (unsigned char)va_arg(*ap, int);
132	break; case LLONG:	arg->i = va_arg(*ap, long long);
133	break; case SIZET:	arg->i = va_arg(*ap, size_t);
134	break; case IMAX:	arg->i = va_arg(*ap, intmax_t);
135	break; case UMAX:	arg->i = va_arg(*ap, uintmax_t);
136	break; case PDIFF:	arg->i = va_arg(*ap, ptrdiff_t);
137	break; case UIPTR:	arg->i = (uintptr_t)va_arg(*ap, void *);
138#if defined(__wasilibc_printscan_no_floating_point)
139	break; case DBL:
140	       case LDBL:
141	floating_point_not_supported();
142#else
143	break; case DBL:	arg->f = va_arg(*ap, double);
144#if defined(__wasilibc_printscan_no_long_double)
145	break; case LDBL:	long_double_not_supported();
146#else
147	break; case LDBL:	arg->f = va_arg(*ap, long double);
148#endif
149#endif
150	}
151}
152
153static void out(FILE *f, const char *s, size_t l)
154{
155	if (!ferror(f)) __fwritex((void *)s, l, f);
156}
157
158static void pad(FILE *f, char c, int w, int l, int fl)
159{
160	char pad[256];
161	if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
162	l = w - l;
163	memset(pad, c, l>sizeof pad ? sizeof pad : l);
164	for (; l >= sizeof pad; l -= sizeof pad)
165		out(f, pad, sizeof pad);
166	out(f, pad, l);
167}
168
169static const char xdigits[16] = {
170	"0123456789ABCDEF"
171};
172
173static char *fmt_x(uintmax_t x, char *s, int lower)
174{
175	for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
176	return s;
177}
178
179static char *fmt_o(uintmax_t x, char *s)
180{
181	for (; x; x>>=3) *--s = '0' + (x&7);
182	return s;
183}
184
185static char *fmt_u(uintmax_t x, char *s)
186{
187	unsigned long y;
188	for (   ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
189	for (y=x;           y; y/=10) *--s = '0' + y%10;
190	return s;
191}
192
193#if !defined(__wasilibc_printscan_no_floating_point)
194/* Do not override this check. The floating point printing code below
195 * depends on the float.h constants being right. If they are wrong, it
196 * may overflow the stack. */
197#if LDBL_MANT_DIG == 53
198#if defined(__wasilibc_printscan_no_long_double)
199typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long_double)];
200#else
201typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
202#endif
203#endif
204
205#if defined(__wasilibc_printscan_no_long_double)
206static int fmt_fp(FILE *f, long_double y, int w, int p, int fl, int t)
207#else
208static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
209#endif
210{
211	uint32_t big[(LDBL_MANT_DIG+28)/29 + 1          // mantissa expansion
212		+ (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
213	uint32_t *a, *d, *r, *z;
214	int e2=0, e, i, j, l;
215	char buf[9+LDBL_MANT_DIG/4], *s;
216	const char *prefix="-0X+0X 0X-0x+0x 0x";
217	int pl;
218	char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
219
220	pl=1;
221	if (signbit(y)) {
222		y=-y;
223	} else if (fl & MARK_POS) {
224		prefix+=3;
225	} else if (fl & PAD_POS) {
226		prefix+=6;
227	} else prefix++, pl=0;
228
229	if (!isfinite(y)) {
230		char *s = (t&32)?"inf":"INF";
231		if (y!=y) s=(t&32)?"nan":"NAN";
232		pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
233		out(f, prefix, pl);
234		out(f, s, 3);
235		pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
236		return MAX(w, 3+pl);
237	}
238
239	y = frexpl(y, &e2) * 2;
240	if (y) e2--;
241
242	if ((t|32)=='a') {
243#if defined(__wasilibc_printscan_no_long_double)
244		long_double round = 8.0;
245#else
246		long double round = 8.0;
247#endif
248		int re;
249
250		if (t&32) prefix += 9;
251		pl += 2;
252
253		if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
254		else re=LDBL_MANT_DIG/4-1-p;
255
256		if (re) {
257			round *= 1<<(LDBL_MANT_DIG%4);
258			while (re--) round*=16;
259			if (*prefix=='-') {
260				y=-y;
261				y-=round;
262				y+=round;
263				y=-y;
264			} else {
265				y+=round;
266				y-=round;
267			}
268		}
269
270		estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
271		if (estr==ebuf) *--estr='0';
272		*--estr = (e2<0 ? '-' : '+');
273		*--estr = t+('p'-'a');
274
275		s=buf;
276		do {
277			int x=y;
278			*s++=xdigits[x]|(t&32);
279			y=16*(y-x);
280			if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
281		} while (y);
282
283		if (p > INT_MAX-2-(ebuf-estr)-pl)
284			return -1;
285		if (p && s-buf-2 < p)
286			l = (p+2) + (ebuf-estr);
287		else
288			l = (s-buf) + (ebuf-estr);
289
290		pad(f, ' ', w, pl+l, fl);
291		out(f, prefix, pl);
292		pad(f, '0', w, pl+l, fl^ZERO_PAD);
293		out(f, buf, s-buf);
294		pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
295		out(f, estr, ebuf-estr);
296		pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
297		return MAX(w, pl+l);
298	}
299	if (p<0) p=6;
300
301	if (y) y *= 0x1p28, e2-=28;
302
303	if (e2<0) a=r=z=big;
304	else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
305
306	do {
307		*z = y;
308		y = 1000000000*(y-*z++);
309	} while (y);
310
311	while (e2>0) {
312		uint32_t carry=0;
313		int sh=MIN(29,e2);
314		for (d=z-1; d>=a; d--) {
315			uint64_t x = ((uint64_t)*d<<sh)+carry;
316			*d = x % 1000000000;
317			carry = x / 1000000000;
318		}
319		if (carry) *--a = carry;
320		while (z>a && !z[-1]) z--;
321		e2-=sh;
322	}
323	while (e2<0) {
324		uint32_t carry=0, *b;
325		int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9;
326		for (d=a; d<z; d++) {
327			uint32_t rm = *d & (1<<sh)-1;
328			*d = (*d>>sh) + carry;
329			carry = (1000000000>>sh) * rm;
330		}
331		if (!*a) a++;
332		if (carry) *z++ = carry;
333		/* Avoid (slow!) computation past requested precision */
334		b = (t|32)=='f' ? r : a;
335		if (z-b > need) z = b+need;
336		e2+=sh;
337	}
338
339	if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
340	else e=0;
341
342	/* Perform rounding: j is precision after the radix (possibly neg) */
343	j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
344	if (j < 9*(z-r-1)) {
345		uint32_t x;
346		/* We avoid C's broken division of negative numbers */
347		d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
348		j += 9*LDBL_MAX_EXP;
349		j %= 9;
350		for (i=10, j++; j<9; i*=10, j++);
351		x = *d % i;
352		/* Are there any significant digits past j? */
353		if (x || d+1!=z) {
354#if defined(__wasilibc_printscan_no_long_double)
355			long_double round = 2/LDBL_EPSILON;
356			long_double small;
357#else
358			long double round = 2/LDBL_EPSILON;
359			long double small;
360#endif
361			if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1)))
362				round += 2;
363			if (x<i/2) small=0x0.8p0;
364			else if (x==i/2 && d+1==z) small=0x1.0p0;
365			else small=0x1.8p0;
366			if (pl && *prefix=='-') round*=-1, small*=-1;
367			*d -= x;
368			/* Decide whether to round by probing round+small */
369			if (round+small != round) {
370				*d = *d + i;
371				while (*d > 999999999) {
372					*d--=0;
373					if (d<a) *--a=0;
374					(*d)++;
375				}
376				for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
377			}
378		}
379		if (z>d+1) z=d+1;
380	}
381	for (; z>a && !z[-1]; z--);
382	
383	if ((t|32)=='g') {
384		if (!p) p++;
385		if (p>e && e>=-4) {
386			t--;
387			p-=e+1;
388		} else {
389			t-=2;
390			p--;
391		}
392		if (!(fl&ALT_FORM)) {
393			/* Count trailing zeros in last place */
394			if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
395			else j=9;
396			if ((t|32)=='f')
397				p = MIN(p,MAX(0,9*(z-r-1)-j));
398			else
399				p = MIN(p,MAX(0,9*(z-r-1)+e-j));
400		}
401	}
402	if (p > INT_MAX-1-(p || (fl&ALT_FORM)))
403		return -1;
404	l = 1 + p + (p || (fl&ALT_FORM));
405	if ((t|32)=='f') {
406		if (e > INT_MAX-l) return -1;
407		if (e>0) l+=e;
408	} else {
409		estr=fmt_u(e<0 ? -e : e, ebuf);
410		while(ebuf-estr<2) *--estr='0';
411		*--estr = (e<0 ? '-' : '+');
412		*--estr = t;
413		if (ebuf-estr > INT_MAX-l) return -1;
414		l += ebuf-estr;
415	}
416
417	if (l > INT_MAX-pl) return -1;
418	pad(f, ' ', w, pl+l, fl);
419	out(f, prefix, pl);
420	pad(f, '0', w, pl+l, fl^ZERO_PAD);
421
422	if ((t|32)=='f') {
423		if (a>r) a=r;
424		for (d=a; d<=r; d++) {
425			char *s = fmt_u(*d, buf+9);
426			if (d!=a) while (s>buf) *--s='0';
427			else if (s==buf+9) *--s='0';
428			out(f, s, buf+9-s);
429		}
430		if (p || (fl&ALT_FORM)) out(f, ".", 1);
431		for (; d<z && p>0; d++, p-=9) {
432			char *s = fmt_u(*d, buf+9);
433			while (s>buf) *--s='0';
434			out(f, s, MIN(9,p));
435		}
436		pad(f, '0', p+9, 9, 0);
437	} else {
438		if (z<=a) z=a+1;
439		for (d=a; d<z && p>=0; d++) {
440			char *s = fmt_u(*d, buf+9);
441			if (s==buf+9) *--s='0';
442			if (d!=a) while (s>buf) *--s='0';
443			else {
444				out(f, s++, 1);
445				if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
446			}
447			out(f, s, MIN(buf+9-s, p));
448			p -= buf+9-s;
449		}
450		pad(f, '0', p+18, 18, 0);
451		out(f, estr, ebuf-estr);
452	}
453
454	pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
455
456	return MAX(w, pl+l);
457}
458#endif
459
460static int getint(char **s) {
461	int i;
462	for (i=0; isdigit(**s); (*s)++) {
463		if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
464		else i = 10*i + (**s-'0');
465	}
466	return i;
467}
468
469static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
470{
471	char *a, *z, *s=(char *)fmt;
472	unsigned l10n=0, fl;
473	int w, p, xp;
474	union arg arg;
475	int argpos;
476	unsigned st, ps;
477	int cnt=0, l=0;
478	size_t i;
479	char buf[sizeof(uintmax_t)*3];
480	const char *prefix;
481	int t, pl;
482	wchar_t wc[2], *ws;
483	char mb[4];
484
485	for (;;) {
486		/* This error is only specified for snprintf, but since it's
487		 * unspecified for other forms, do the same. Stop immediately
488		 * on overflow; otherwise %n could produce wrong results. */
489		if (l > INT_MAX - cnt) goto overflow;
490
491		/* Update output count, end loop when fmt is exhausted */
492		cnt += l;
493		if (!*s) break;
494
495		/* Handle literal text and %% format specifiers */
496		for (a=s; *s && *s!='%'; s++);
497		for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
498		if (z-a > INT_MAX-cnt) goto overflow;
499		l = z-a;
500		if (f) out(f, a, l);
501		if (l) continue;
502
503		if (isdigit(s[1]) && s[2]=='$') {
504			l10n=1;
505			argpos = s[1]-'0';
506			s+=3;
507		} else {
508			argpos = -1;
509			s++;
510		}
511
512		/* Read modifier flags */
513		for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
514			fl |= 1U<<*s-' ';
515
516		/* Read field width */
517		if (*s=='*') {
518			if (isdigit(s[1]) && s[2]=='$') {
519				l10n=1;
520				if (!f) nl_type[s[1]-'0'] = INT, w = 0;
521				else w = nl_arg[s[1]-'0'].i;
522				s+=3;
523			} else if (!l10n) {
524				w = f ? va_arg(*ap, int) : 0;
525				s++;
526			} else goto inval;
527			if (w<0) fl|=LEFT_ADJ, w=-w;
528		} else if ((w=getint(&s))<0) goto overflow;
529
530		/* Read precision */
531		if (*s=='.' && s[1]=='*') {
532			if (isdigit(s[2]) && s[3]=='$') {
533				if (!f) nl_type[s[2]-'0'] = INT, p = 0;
534				else p = nl_arg[s[2]-'0'].i;
535				s+=4;
536			} else if (!l10n) {
537				p = f ? va_arg(*ap, int) : 0;
538				s+=2;
539			} else goto inval;
540			xp = (p>=0);
541		} else if (*s=='.') {
542			s++;
543			p = getint(&s);
544			xp = 1;
545		} else {
546			p = -1;
547			xp = 0;
548		}
549
550		/* Format specifier state machine */
551		st=0;
552		do {
553			if (OOB(*s)) goto inval;
554			ps=st;
555			st=states[st]S(*s++);
556		} while (st-1<STOP);
557		if (!st) goto inval;
558
559		/* Check validity of argument type (nl/normal) */
560		if (st==NOARG) {
561			if (argpos>=0) goto inval;
562		} else {
563			if (argpos>=0) {
564				if (!f) nl_type[argpos]=st;
565				else arg=nl_arg[argpos];
566			} else if (f) pop_arg(&arg, st, ap);
567			else return 0;
568		}
569
570		if (!f) continue;
571
572		/* Do not process any new directives once in error state. */
573		if (ferror(f)) return -1;
574
575		z = buf + sizeof(buf);
576		prefix = "-+   0X0x";
577		pl = 0;
578		t = s[-1];
579
580		/* Transform ls,lc -> S,C */
581		if (ps && (t&15)==3) t&=~32;
582
583		/* - and 0 flags are mutually exclusive */
584		if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
585
586		switch(t) {
587		case 'n':
588			switch(ps) {
589			case BARE: *(int *)arg.p = cnt; break;
590			case LPRE: *(long *)arg.p = cnt; break;
591			case LLPRE: *(long long *)arg.p = cnt; break;
592			case HPRE: *(unsigned short *)arg.p = cnt; break;
593			case HHPRE: *(unsigned char *)arg.p = cnt; break;
594			case ZTPRE: *(size_t *)arg.p = cnt; break;
595			case JPRE: *(uintmax_t *)arg.p = cnt; break;
596			}
597			continue;
598		case 'p':
599			p = MAX(p, 2*sizeof(void*));
600			t = 'x';
601			fl |= ALT_FORM;
602		case 'x': case 'X':
603			a = fmt_x(arg.i, z, t&32);
604			if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
605			if (0) {
606		case 'o':
607			a = fmt_o(arg.i, z);
608			if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
609			} if (0) {
610		case 'd': case 'i':
611			pl=1;
612			if (arg.i>INTMAX_MAX) {
613				arg.i=-arg.i;
614			} else if (fl & MARK_POS) {
615				prefix++;
616			} else if (fl & PAD_POS) {
617				prefix+=2;
618			} else pl=0;
619		case 'u':
620			a = fmt_u(arg.i, z);
621			}
622			if (xp && p<0) goto overflow;
623			if (xp) fl &= ~ZERO_PAD;
624			if (!arg.i && !p) {
625				a=z;
626				break;
627			}
628			p = MAX(p, z-a + !arg.i);
629			break;
630		narrow_c:
631		case 'c':
632			*(a=z-(p=1))=arg.i;
633			fl &= ~ZERO_PAD;
634			break;
635		case 'm':
636			if (1) a = strerror(errno); else
637		case 's':
638			a = arg.p ? arg.p : "(null)";
639			z = a + strnlen(a, p<0 ? INT_MAX : p);
640			if (p<0 && *z) goto overflow;
641			p = z-a;
642			fl &= ~ZERO_PAD;
643			break;
644		case 'C':
645			if (!arg.i) goto narrow_c;
646			wc[0] = arg.i;
647			wc[1] = 0;
648			arg.p = wc;
649			p = -1;
650		case 'S':
651			ws = arg.p;
652			for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l);
653			if (l<0) return -1;
654			if (i > INT_MAX) goto overflow;
655			p = i;
656			pad(f, ' ', w, p, fl);
657			ws = arg.p;
658			for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
659				out(f, mb, l);
660			pad(f, ' ', w, p, fl^LEFT_ADJ);
661			l = w>p ? w : p;
662			continue;
663#if !defined(__wasilibc_printscan_no_floating_point)
664		case 'e': case 'f': case 'g': case 'a':
665		case 'E': case 'F': case 'G': case 'A':
666			if (xp && p<0) goto overflow;
667			l = fmt_fp(f, arg.f, w, p, fl, t);
668			if (l<0) goto overflow;
669			continue;
670#endif
671		}
672
673		if (p < z-a) p = z-a;
674		if (p > INT_MAX-pl) goto overflow;
675		if (w < pl+p) w = pl+p;
676		if (w > INT_MAX-cnt) goto overflow;
677
678		pad(f, ' ', w, pl+p, fl);
679		out(f, prefix, pl);
680		pad(f, '0', w, pl+p, fl^ZERO_PAD);
681		pad(f, '0', p, z-a, 0);
682		out(f, a, z-a);
683		pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
684
685		l = w;
686	}
687
688	if (f) return cnt;
689	if (!l10n) return 0;
690
691	for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
692		pop_arg(nl_arg+i, nl_type[i], ap);
693	for (; i<=NL_ARGMAX && !nl_type[i]; i++);
694	if (i<=NL_ARGMAX) goto inval;
695	return 1;
696
697inval:
698	errno = EINVAL;
699	return -1;
700overflow:
701	errno = EOVERFLOW;
702	return -1;
703}
704
705int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
706{
707	va_list ap2;
708	int nl_type[NL_ARGMAX+1] = {0};
709	union arg nl_arg[NL_ARGMAX+1];
710	unsigned char internal_buf[80], *saved_buf = 0;
711	int olderr;
712	int ret;
713
714	/* the copy allows passing va_list* even if va_list is an array */
715	va_copy(ap2, ap);
716	if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
717		va_end(ap2);
718		return -1;
719	}
720
721	FLOCK(f);
722	olderr = f->flags & F_ERR;
723	f->flags &= ~F_ERR;
724	if (!f->buf_size) {
725		saved_buf = f->buf;
726		f->buf = internal_buf;
727		f->buf_size = sizeof internal_buf;
728		f->wpos = f->wbase = f->wend = 0;
729	}
730	if (!f->wend && __towrite(f)) ret = -1;
731	else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
732	if (saved_buf) {
733		f->write(f, 0, 0);
734		if (!f->wpos) ret = -1;
735		f->buf = saved_buf;
736		f->buf_size = 0;
737		f->wpos = f->wbase = f->wend = 0;
738	}
739	if (ferror(f)) ret = -1;
740	f->flags |= olderr;
741	FUNLOCK(f);
742	va_end(ap2);
743	return ret;
744}