| 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 | |
| 34 | enum { |
| 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 | |
| 49 | static 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 | |
| 102 | union arg |
| 103 | { |
| 104 | 	uintmax_t i; |
| 105 | 	long double f; |
| 106 | 	void *p; |
| 107 | }; |
| 108 | |
| 109 | static 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 | |
| 133 | static void out(FILE *f, const char *s, size_t l) |
| 134 | { |
| 135 | 	if (!ferror(f)) __fwritex((void *)s, l, f); |
| 136 | } |
| 137 | |
| 138 | static 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 | |
| 149 | static const char xdigits[16] = { |
| 150 | 	"0123456789ABCDEF" |
| 151 | }; |
| 152 | |
| 153 | static 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 | |
| 159 | static char *fmt_o(uintmax_t x, char *s) |
| 160 | { |
| 161 | 	for (; x; x>>=3) *--s = '0' + (x&7); |
| 162 | 	return s; |
| 163 | } |
| 164 | |
| 165 | static 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 |
| 177 | typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; |
| 178 | #endif |
| 179 | |
| 180 | static 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 | |
| 421 | static 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 | |
| 430 | static 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 | |
| 656 | inval: |
| 657 | 	errno = EINVAL; |
| 658 | 	return -1; |
| 659 | overflow: |
| 660 | 	errno = EOVERFLOW; |
| 661 | 	return -1; |
| 662 | } |
| 663 | |
| 664 | int 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 | } |