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