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