1570af302Sopenharmony_ci#include "stdio_impl.h" 2570af302Sopenharmony_ci#include <errno.h> 3570af302Sopenharmony_ci#include <ctype.h> 4570af302Sopenharmony_ci#include <limits.h> 5570af302Sopenharmony_ci#include <string.h> 6570af302Sopenharmony_ci#include <stdarg.h> 7570af302Sopenharmony_ci#include <stddef.h> 8570af302Sopenharmony_ci#include <stdlib.h> 9570af302Sopenharmony_ci#include <wchar.h> 10570af302Sopenharmony_ci#include <inttypes.h> 11570af302Sopenharmony_ci#include <math.h> 12570af302Sopenharmony_ci#include <float.h> 13570af302Sopenharmony_ci#include <sys/ioctl.h> 14570af302Sopenharmony_ci 15570af302Sopenharmony_ci/* Some useful macros */ 16570af302Sopenharmony_ci 17570af302Sopenharmony_ci#define MAX(a,b) ((a)>(b) ? (a) : (b)) 18570af302Sopenharmony_ci#define MIN(a,b) ((a)<(b) ? (a) : (b)) 19570af302Sopenharmony_ci 20570af302Sopenharmony_ci/* Convenient bit representation for modifier flags, which all fall 21570af302Sopenharmony_ci * within 31 codepoints of the space character. */ 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci#define ALT_FORM (1U<<('#'-' ')) 24570af302Sopenharmony_ci#define ZERO_PAD (1U<<('0'-' ')) 25570af302Sopenharmony_ci#define LEFT_ADJ (1U<<('-'-' ')) 26570af302Sopenharmony_ci#define PAD_POS (1U<<(' '-' ')) 27570af302Sopenharmony_ci#define MARK_POS (1U<<('+'-' ')) 28570af302Sopenharmony_ci#define GROUPED (1U<<('\''-' ')) 29570af302Sopenharmony_ci 30570af302Sopenharmony_ci#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) 31570af302Sopenharmony_ci 32570af302Sopenharmony_ci/* Redefine the CHAR type that defined in los_typedef.h and introduced 33570af302Sopenharmony_ci * in by limit.h to avoid conflicts with the following enum definition. */ 34570af302Sopenharmony_ci#define CHAR _CHAR 35570af302Sopenharmony_ci 36570af302Sopenharmony_ci/* State machine to accept length modifiers + conversion specifiers. 37570af302Sopenharmony_ci * Result is 0 on failure, or an argument type to pop on success. */ 38570af302Sopenharmony_ci 39570af302Sopenharmony_cienum { 40570af302Sopenharmony_ci BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, 41570af302Sopenharmony_ci ZTPRE, JPRE, 42570af302Sopenharmony_ci STOP, 43570af302Sopenharmony_ci PTR, INT, UINT, ULLONG, 44570af302Sopenharmony_ci LONG, ULONG, 45570af302Sopenharmony_ci SHORT, USHORT, CHAR, UCHAR, 46570af302Sopenharmony_ci LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, 47570af302Sopenharmony_ci DBL, LDBL, 48570af302Sopenharmony_ci NOARG, 49570af302Sopenharmony_ci MAXSTATE 50570af302Sopenharmony_ci}; 51570af302Sopenharmony_ci 52570af302Sopenharmony_ci#define S(x) [(x)-'A'] 53570af302Sopenharmony_ci 54570af302Sopenharmony_cistatic const unsigned char states[]['z'-'A'+1] = { 55570af302Sopenharmony_ci { /* 0: bare types */ 56570af302Sopenharmony_ci S('d') = INT, S('i') = INT, 57570af302Sopenharmony_ci S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, 58570af302Sopenharmony_ci S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, 59570af302Sopenharmony_ci S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, 60570af302Sopenharmony_ci S('c') = CHAR, S('C') = INT, 61570af302Sopenharmony_ci S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, 62570af302Sopenharmony_ci S('m') = NOARG, 63570af302Sopenharmony_ci S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, 64570af302Sopenharmony_ci S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, 65570af302Sopenharmony_ci }, { /* 1: l-prefixed */ 66570af302Sopenharmony_ci S('d') = LONG, S('i') = LONG, 67570af302Sopenharmony_ci S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, 68570af302Sopenharmony_ci S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, 69570af302Sopenharmony_ci S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, 70570af302Sopenharmony_ci S('c') = INT, S('s') = PTR, S('n') = PTR, 71570af302Sopenharmony_ci S('l') = LLPRE, 72570af302Sopenharmony_ci }, { /* 2: ll-prefixed */ 73570af302Sopenharmony_ci S('d') = LLONG, S('i') = LLONG, 74570af302Sopenharmony_ci S('o') = ULLONG, S('u') = ULLONG, 75570af302Sopenharmony_ci S('x') = ULLONG, S('X') = ULLONG, 76570af302Sopenharmony_ci S('n') = PTR, 77570af302Sopenharmony_ci }, { /* 3: h-prefixed */ 78570af302Sopenharmony_ci S('d') = SHORT, S('i') = SHORT, 79570af302Sopenharmony_ci S('o') = USHORT, S('u') = USHORT, 80570af302Sopenharmony_ci S('x') = USHORT, S('X') = USHORT, 81570af302Sopenharmony_ci S('n') = PTR, 82570af302Sopenharmony_ci S('h') = HHPRE, 83570af302Sopenharmony_ci }, { /* 4: hh-prefixed */ 84570af302Sopenharmony_ci S('d') = CHAR, S('i') = CHAR, 85570af302Sopenharmony_ci S('o') = UCHAR, S('u') = UCHAR, 86570af302Sopenharmony_ci S('x') = UCHAR, S('X') = UCHAR, 87570af302Sopenharmony_ci S('n') = PTR, 88570af302Sopenharmony_ci }, { /* 5: L-prefixed */ 89570af302Sopenharmony_ci S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, 90570af302Sopenharmony_ci S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, 91570af302Sopenharmony_ci S('n') = PTR, 92570af302Sopenharmony_ci }, { /* 6: z- or t-prefixed (assumed to be same size) */ 93570af302Sopenharmony_ci S('d') = PDIFF, S('i') = PDIFF, 94570af302Sopenharmony_ci S('o') = SIZET, S('u') = SIZET, 95570af302Sopenharmony_ci S('x') = SIZET, S('X') = SIZET, 96570af302Sopenharmony_ci S('n') = PTR, 97570af302Sopenharmony_ci }, { /* 7: j-prefixed */ 98570af302Sopenharmony_ci S('d') = IMAX, S('i') = IMAX, 99570af302Sopenharmony_ci S('o') = UMAX, S('u') = UMAX, 100570af302Sopenharmony_ci S('x') = UMAX, S('X') = UMAX, 101570af302Sopenharmony_ci S('n') = PTR, 102570af302Sopenharmony_ci } 103570af302Sopenharmony_ci}; 104570af302Sopenharmony_ci 105570af302Sopenharmony_ci#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') 106570af302Sopenharmony_ci 107570af302Sopenharmony_ciunion arg 108570af302Sopenharmony_ci{ 109570af302Sopenharmony_ci uintmax_t i; 110570af302Sopenharmony_ci long double f; 111570af302Sopenharmony_ci void *p; 112570af302Sopenharmony_ci}; 113570af302Sopenharmony_ci 114570af302Sopenharmony_cistatic void pop_arg(union arg *arg, int type, va_list *ap) 115570af302Sopenharmony_ci{ 116570af302Sopenharmony_ci switch (type) { 117570af302Sopenharmony_ci case PTR: arg->p = va_arg(*ap, void *); 118570af302Sopenharmony_ci break; case INT: arg->i = va_arg(*ap, int); 119570af302Sopenharmony_ci break; case UINT: arg->i = va_arg(*ap, unsigned int); 120570af302Sopenharmony_ci break; case LONG: arg->i = va_arg(*ap, long); 121570af302Sopenharmony_ci break; case ULONG: arg->i = va_arg(*ap, unsigned long); 122570af302Sopenharmony_ci break; case ULLONG: arg->i = va_arg(*ap, unsigned long long); 123570af302Sopenharmony_ci break; case SHORT: arg->i = (short)va_arg(*ap, int); 124570af302Sopenharmony_ci break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int); 125570af302Sopenharmony_ci break; case CHAR: arg->i = (signed char)va_arg(*ap, int); 126570af302Sopenharmony_ci break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int); 127570af302Sopenharmony_ci break; case LLONG: arg->i = va_arg(*ap, long long); 128570af302Sopenharmony_ci break; case SIZET: arg->i = va_arg(*ap, size_t); 129570af302Sopenharmony_ci break; case IMAX: arg->i = va_arg(*ap, intmax_t); 130570af302Sopenharmony_ci break; case UMAX: arg->i = va_arg(*ap, uintmax_t); 131570af302Sopenharmony_ci break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t); 132570af302Sopenharmony_ci break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *); 133570af302Sopenharmony_ci break; case DBL: arg->f = va_arg(*ap, double); 134570af302Sopenharmony_ci break; case LDBL: arg->f = va_arg(*ap, long double); 135570af302Sopenharmony_ci } 136570af302Sopenharmony_ci} 137570af302Sopenharmony_ci 138570af302Sopenharmony_cistatic void out(FILE *f, const char *s, size_t l) 139570af302Sopenharmony_ci{ 140570af302Sopenharmony_ci if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); 141570af302Sopenharmony_ci} 142570af302Sopenharmony_ci 143570af302Sopenharmony_cistatic void pad(FILE *f, char c, int w, int l, int fl) 144570af302Sopenharmony_ci{ 145570af302Sopenharmony_ci char pad[256]; 146570af302Sopenharmony_ci if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; 147570af302Sopenharmony_ci l = w - l; 148570af302Sopenharmony_ci memset(pad, c, l>sizeof pad ? sizeof pad : l); 149570af302Sopenharmony_ci for (; l >= sizeof pad; l -= sizeof pad) 150570af302Sopenharmony_ci out(f, pad, sizeof pad); 151570af302Sopenharmony_ci out(f, pad, l); 152570af302Sopenharmony_ci} 153570af302Sopenharmony_ci 154570af302Sopenharmony_cistatic const char xdigits[16] = { 155570af302Sopenharmony_ci "0123456789ABCDEF" 156570af302Sopenharmony_ci}; 157570af302Sopenharmony_ci 158570af302Sopenharmony_cistatic char *fmt_x(uintmax_t x, char *s, int lower) 159570af302Sopenharmony_ci{ 160570af302Sopenharmony_ci for (; x; x>>=4) *--s = xdigits[(x&15)]|lower; 161570af302Sopenharmony_ci return s; 162570af302Sopenharmony_ci} 163570af302Sopenharmony_ci 164570af302Sopenharmony_cistatic char *fmt_o(uintmax_t x, char *s) 165570af302Sopenharmony_ci{ 166570af302Sopenharmony_ci for (; x; x>>=3) *--s = '0' + (x&7); 167570af302Sopenharmony_ci return s; 168570af302Sopenharmony_ci} 169570af302Sopenharmony_ci 170570af302Sopenharmony_cistatic char *fmt_u(uintmax_t x, char *s) 171570af302Sopenharmony_ci{ 172570af302Sopenharmony_ci unsigned long y; 173570af302Sopenharmony_ci for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10; 174570af302Sopenharmony_ci for (y=x; y; y/=10) *--s = '0' + y%10; 175570af302Sopenharmony_ci return s; 176570af302Sopenharmony_ci} 177570af302Sopenharmony_ci 178570af302Sopenharmony_ci/* Do not override this check. The floating point printing code below 179570af302Sopenharmony_ci * depends on the float.h constants being right. If they are wrong, it 180570af302Sopenharmony_ci * may overflow the stack. */ 181570af302Sopenharmony_ci#if LDBL_MANT_DIG == 53 182570af302Sopenharmony_ci// typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; 183570af302Sopenharmony_ci#endif 184570af302Sopenharmony_ci 185570af302Sopenharmony_cistatic int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) 186570af302Sopenharmony_ci{ 187570af302Sopenharmony_ci uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion 188570af302Sopenharmony_ci + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion 189570af302Sopenharmony_ci uint32_t *a, *d, *r, *z; 190570af302Sopenharmony_ci int e2=0, e, i, j, l; 191570af302Sopenharmony_ci char buf[9+LDBL_MANT_DIG/4], *s; 192570af302Sopenharmony_ci const char *prefix="-0X+0X 0X-0x+0x 0x"; 193570af302Sopenharmony_ci int pl; 194570af302Sopenharmony_ci char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)]; 195570af302Sopenharmony_ci char *estr = NULL; 196570af302Sopenharmony_ci 197570af302Sopenharmony_ci pl=1; 198570af302Sopenharmony_ci if (signbit(y)) { 199570af302Sopenharmony_ci y=-y; 200570af302Sopenharmony_ci } else if (fl & MARK_POS) { 201570af302Sopenharmony_ci prefix+=3; 202570af302Sopenharmony_ci } else if (fl & PAD_POS) { 203570af302Sopenharmony_ci prefix+=6; 204570af302Sopenharmony_ci } else prefix++, pl=0; 205570af302Sopenharmony_ci 206570af302Sopenharmony_ci if (!isfinite(y)) { 207570af302Sopenharmony_ci char *s = (t&32)?"inf":"INF"; 208570af302Sopenharmony_ci if (y!=y) s=(t&32)?"nan":"NAN"; 209570af302Sopenharmony_ci pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); 210570af302Sopenharmony_ci out(f, prefix, pl); 211570af302Sopenharmony_ci out(f, s, 3); 212570af302Sopenharmony_ci pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); 213570af302Sopenharmony_ci return MAX(w, 3+pl); 214570af302Sopenharmony_ci } 215570af302Sopenharmony_ci 216570af302Sopenharmony_ci y = frexpl(y, &e2) * 2; 217570af302Sopenharmony_ci if (y) e2--; 218570af302Sopenharmony_ci 219570af302Sopenharmony_ci if ((t|32)=='a') { 220570af302Sopenharmony_ci long double round = 8.0; 221570af302Sopenharmony_ci int re; 222570af302Sopenharmony_ci 223570af302Sopenharmony_ci if (t&32) prefix += 9; 224570af302Sopenharmony_ci pl += 2; 225570af302Sopenharmony_ci 226570af302Sopenharmony_ci if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; 227570af302Sopenharmony_ci else re=LDBL_MANT_DIG/4-1-p; 228570af302Sopenharmony_ci 229570af302Sopenharmony_ci if (re) { 230570af302Sopenharmony_ci round *= 1<<(LDBL_MANT_DIG%4); 231570af302Sopenharmony_ci while (re--) round*=16; 232570af302Sopenharmony_ci if (*prefix=='-') { 233570af302Sopenharmony_ci y=-y; 234570af302Sopenharmony_ci y-=round; 235570af302Sopenharmony_ci y+=round; 236570af302Sopenharmony_ci y=-y; 237570af302Sopenharmony_ci } else { 238570af302Sopenharmony_ci y+=round; 239570af302Sopenharmony_ci y-=round; 240570af302Sopenharmony_ci } 241570af302Sopenharmony_ci } 242570af302Sopenharmony_ci 243570af302Sopenharmony_ci estr=fmt_u(e2<0 ? -e2 : e2, ebuf); 244570af302Sopenharmony_ci if (estr==ebuf) *--estr='0'; 245570af302Sopenharmony_ci *--estr = (e2<0 ? '-' : '+'); 246570af302Sopenharmony_ci *--estr = t+('p'-'a'); 247570af302Sopenharmony_ci 248570af302Sopenharmony_ci s=buf; 249570af302Sopenharmony_ci do { 250570af302Sopenharmony_ci int x=y; 251570af302Sopenharmony_ci *s++=xdigits[x]|(t&32); 252570af302Sopenharmony_ci y=16*(y-x); 253570af302Sopenharmony_ci if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; 254570af302Sopenharmony_ci } while (y); 255570af302Sopenharmony_ci 256570af302Sopenharmony_ci if (p > INT_MAX-2-(ebuf-estr)-pl) 257570af302Sopenharmony_ci return -1; 258570af302Sopenharmony_ci if (p && s-buf-2 < p) 259570af302Sopenharmony_ci l = (p+2) + (ebuf-estr); 260570af302Sopenharmony_ci else 261570af302Sopenharmony_ci l = (s-buf) + (ebuf-estr); 262570af302Sopenharmony_ci 263570af302Sopenharmony_ci pad(f, ' ', w, pl+l, fl); 264570af302Sopenharmony_ci out(f, prefix, pl); 265570af302Sopenharmony_ci pad(f, '0', w, pl+l, fl^ZERO_PAD); 266570af302Sopenharmony_ci out(f, buf, s-buf); 267570af302Sopenharmony_ci pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); 268570af302Sopenharmony_ci out(f, estr, ebuf-estr); 269570af302Sopenharmony_ci pad(f, ' ', w, pl+l, fl^LEFT_ADJ); 270570af302Sopenharmony_ci return MAX(w, pl+l); 271570af302Sopenharmony_ci } 272570af302Sopenharmony_ci if (p<0) p=6; 273570af302Sopenharmony_ci 274570af302Sopenharmony_ci if (y) y *= 0x1p28, e2-=28; 275570af302Sopenharmony_ci 276570af302Sopenharmony_ci if (e2<0) a=r=z=big; 277570af302Sopenharmony_ci else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; 278570af302Sopenharmony_ci 279570af302Sopenharmony_ci do { 280570af302Sopenharmony_ci *z = y; 281570af302Sopenharmony_ci y = 1000000000*(y-*z++); 282570af302Sopenharmony_ci } while (y); 283570af302Sopenharmony_ci 284570af302Sopenharmony_ci while (e2>0) { 285570af302Sopenharmony_ci uint32_t carry=0; 286570af302Sopenharmony_ci int sh=MIN(29,e2); 287570af302Sopenharmony_ci for (d=z-1; d>=a; d--) { 288570af302Sopenharmony_ci uint64_t x = ((uint64_t)*d<<sh)+carry; 289570af302Sopenharmony_ci *d = x % 1000000000; 290570af302Sopenharmony_ci carry = x / 1000000000; 291570af302Sopenharmony_ci } 292570af302Sopenharmony_ci if (carry) *--a = carry; 293570af302Sopenharmony_ci while (z>a && !z[-1]) z--; 294570af302Sopenharmony_ci e2-=sh; 295570af302Sopenharmony_ci } 296570af302Sopenharmony_ci while (e2<0) { 297570af302Sopenharmony_ci uint32_t carry=0, *b; 298570af302Sopenharmony_ci int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9; 299570af302Sopenharmony_ci for (d=a; d<z; d++) { 300570af302Sopenharmony_ci uint32_t rm = *d & ((1<<sh)-1); 301570af302Sopenharmony_ci *d = (*d>>sh) + carry; 302570af302Sopenharmony_ci carry = (1000000000>>sh) * rm; 303570af302Sopenharmony_ci } 304570af302Sopenharmony_ci if (!*a) a++; 305570af302Sopenharmony_ci if (carry) *z++ = carry; 306570af302Sopenharmony_ci /* Avoid (slow!) computation past requested precision */ 307570af302Sopenharmony_ci b = (t|32)=='f' ? r : a; 308570af302Sopenharmony_ci if (z-b > need) z = b+need; 309570af302Sopenharmony_ci e2+=sh; 310570af302Sopenharmony_ci } 311570af302Sopenharmony_ci 312570af302Sopenharmony_ci if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++); 313570af302Sopenharmony_ci else e=0; 314570af302Sopenharmony_ci 315570af302Sopenharmony_ci /* Perform rounding: j is precision after the radix (possibly neg) */ 316570af302Sopenharmony_ci j = p - ((t|32)!='f')*e - ((t|32)=='g' && p); 317570af302Sopenharmony_ci if (j < 9*(z-r-1)) { 318570af302Sopenharmony_ci uint32_t x; 319570af302Sopenharmony_ci /* We avoid C's broken division of negative numbers */ 320570af302Sopenharmony_ci d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); 321570af302Sopenharmony_ci j += 9*LDBL_MAX_EXP; 322570af302Sopenharmony_ci j %= 9; 323570af302Sopenharmony_ci for (i=10, j++; j<9; i*=10, j++); 324570af302Sopenharmony_ci x = *d % i; 325570af302Sopenharmony_ci /* Are there any significant digits past j? */ 326570af302Sopenharmony_ci if (x || d+1!=z) { 327570af302Sopenharmony_ci long double round = 2/LDBL_EPSILON; 328570af302Sopenharmony_ci long double small; 329570af302Sopenharmony_ci if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1))) 330570af302Sopenharmony_ci round += 2; 331570af302Sopenharmony_ci if (x<i/2) small=0x0.8p0; 332570af302Sopenharmony_ci else if (x==i/2 && d+1==z) small=0x1.0p0; 333570af302Sopenharmony_ci else small=0x1.8p0; 334570af302Sopenharmony_ci if (pl && *prefix=='-') round*=-1, small*=-1; 335570af302Sopenharmony_ci *d -= x; 336570af302Sopenharmony_ci /* Decide whether to round by probing round+small */ 337570af302Sopenharmony_ci if (round+small != round) { 338570af302Sopenharmony_ci *d = *d + i; 339570af302Sopenharmony_ci while (*d > 999999999) { 340570af302Sopenharmony_ci *d--=0; 341570af302Sopenharmony_ci if (d<a) *--a=0; 342570af302Sopenharmony_ci (*d)++; 343570af302Sopenharmony_ci } 344570af302Sopenharmony_ci for (i=10, e=9*(r-a); *a>=i; i*=10, e++); 345570af302Sopenharmony_ci } 346570af302Sopenharmony_ci } 347570af302Sopenharmony_ci if (z>d+1) z=d+1; 348570af302Sopenharmony_ci } 349570af302Sopenharmony_ci for (; z>a && !z[-1]; z--); 350570af302Sopenharmony_ci 351570af302Sopenharmony_ci if ((t|32)=='g') { 352570af302Sopenharmony_ci if (!p) p++; 353570af302Sopenharmony_ci if (p>e && e>=-4) { 354570af302Sopenharmony_ci t--; 355570af302Sopenharmony_ci p-=e+1; 356570af302Sopenharmony_ci } else { 357570af302Sopenharmony_ci t-=2; 358570af302Sopenharmony_ci p--; 359570af302Sopenharmony_ci } 360570af302Sopenharmony_ci if (!(fl&ALT_FORM)) { 361570af302Sopenharmony_ci /* Count trailing zeros in last place */ 362570af302Sopenharmony_ci if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); 363570af302Sopenharmony_ci else j=9; 364570af302Sopenharmony_ci if ((t|32)=='f') 365570af302Sopenharmony_ci p = MIN(p,MAX(0,9*(z-r-1)-j)); 366570af302Sopenharmony_ci else 367570af302Sopenharmony_ci p = MIN(p,MAX(0,9*(z-r-1)+e-j)); 368570af302Sopenharmony_ci } 369570af302Sopenharmony_ci } 370570af302Sopenharmony_ci if (p > INT_MAX-1-(p || (fl&ALT_FORM))) 371570af302Sopenharmony_ci return -1; 372570af302Sopenharmony_ci l = 1 + p + (p || (fl&ALT_FORM)); 373570af302Sopenharmony_ci if ((t|32)=='f') { 374570af302Sopenharmony_ci if (e > INT_MAX-l) return -1; 375570af302Sopenharmony_ci if (e>0) l+=e; 376570af302Sopenharmony_ci } else { 377570af302Sopenharmony_ci estr=fmt_u(e<0 ? -e : e, ebuf); 378570af302Sopenharmony_ci while(ebuf-estr<2) *--estr='0'; 379570af302Sopenharmony_ci *--estr = (e<0 ? '-' : '+'); 380570af302Sopenharmony_ci *--estr = t; 381570af302Sopenharmony_ci if (ebuf-estr > INT_MAX-l) return -1; 382570af302Sopenharmony_ci l += ebuf-estr; 383570af302Sopenharmony_ci } 384570af302Sopenharmony_ci 385570af302Sopenharmony_ci if (l > INT_MAX-pl) return -1; 386570af302Sopenharmony_ci pad(f, ' ', w, pl+l, fl); 387570af302Sopenharmony_ci out(f, prefix, pl); 388570af302Sopenharmony_ci pad(f, '0', w, pl+l, fl^ZERO_PAD); 389570af302Sopenharmony_ci 390570af302Sopenharmony_ci if ((t|32)=='f') { 391570af302Sopenharmony_ci if (a>r) a=r; 392570af302Sopenharmony_ci for (d=a; d<=r; d++) { 393570af302Sopenharmony_ci char *s = fmt_u(*d, buf+9); 394570af302Sopenharmony_ci if (d!=a) while (s>buf) *--s='0'; 395570af302Sopenharmony_ci else if (s==buf+9) *--s='0'; 396570af302Sopenharmony_ci out(f, s, buf+9-s); 397570af302Sopenharmony_ci } 398570af302Sopenharmony_ci if (p || (fl&ALT_FORM)) out(f, ".", 1); 399570af302Sopenharmony_ci for (; d<z && p>0; d++, p-=9) { 400570af302Sopenharmony_ci char *s = fmt_u(*d, buf+9); 401570af302Sopenharmony_ci while (s>buf) *--s='0'; 402570af302Sopenharmony_ci out(f, s, MIN(9,p)); 403570af302Sopenharmony_ci } 404570af302Sopenharmony_ci pad(f, '0', p+9, 9, 0); 405570af302Sopenharmony_ci } else { 406570af302Sopenharmony_ci if (z<=a) z=a+1; 407570af302Sopenharmony_ci for (d=a; d<z && p>=0; d++) { 408570af302Sopenharmony_ci char *s = fmt_u(*d, buf+9); 409570af302Sopenharmony_ci if (s==buf+9) *--s='0'; 410570af302Sopenharmony_ci if (d!=a) while (s>buf) *--s='0'; 411570af302Sopenharmony_ci else { 412570af302Sopenharmony_ci out(f, s++, 1); 413570af302Sopenharmony_ci if (p>0||(fl&ALT_FORM)) out(f, ".", 1); 414570af302Sopenharmony_ci } 415570af302Sopenharmony_ci out(f, s, MIN(buf+9-s, p)); 416570af302Sopenharmony_ci p -= buf+9-s; 417570af302Sopenharmony_ci } 418570af302Sopenharmony_ci pad(f, '0', p+18, 18, 0); 419570af302Sopenharmony_ci out(f, estr, ebuf-estr); 420570af302Sopenharmony_ci } 421570af302Sopenharmony_ci 422570af302Sopenharmony_ci pad(f, ' ', w, pl+l, fl^LEFT_ADJ); 423570af302Sopenharmony_ci 424570af302Sopenharmony_ci return MAX(w, pl+l); 425570af302Sopenharmony_ci} 426570af302Sopenharmony_ci 427570af302Sopenharmony_cistatic int getint(char **s) { 428570af302Sopenharmony_ci int i; 429570af302Sopenharmony_ci for (i=0; isdigit(**s); (*s)++) { 430570af302Sopenharmony_ci if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1; 431570af302Sopenharmony_ci else i = 10*i + (**s-'0'); 432570af302Sopenharmony_ci } 433570af302Sopenharmony_ci return i; 434570af302Sopenharmony_ci} 435570af302Sopenharmony_ci 436570af302Sopenharmony_cistatic int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type) 437570af302Sopenharmony_ci{ 438570af302Sopenharmony_ci char *a, *z, *s=(char *)fmt; 439570af302Sopenharmony_ci unsigned l10n=0, fl; 440570af302Sopenharmony_ci int w, p, xp; 441570af302Sopenharmony_ci union arg arg; 442570af302Sopenharmony_ci int argpos; 443570af302Sopenharmony_ci unsigned st, ps; 444570af302Sopenharmony_ci int cnt=0, l=0; 445570af302Sopenharmony_ci size_t i; 446570af302Sopenharmony_ci char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; 447570af302Sopenharmony_ci const char *prefix; 448570af302Sopenharmony_ci int t, pl; 449570af302Sopenharmony_ci wchar_t wc[2], *ws; 450570af302Sopenharmony_ci char mb[4]; 451570af302Sopenharmony_ci#ifdef OS_SUPPORT_FS 452570af302Sopenharmony_ci struct winsize wsz; 453570af302Sopenharmony_ci 454570af302Sopenharmony_ci if (f && (f->write == __stdout_write)) { 455570af302Sopenharmony_ci f->lbf = '\n'; 456570af302Sopenharmony_ci f->write = __stdio_write; 457570af302Sopenharmony_ci f->wpos = f->wbase = f->buf; 458570af302Sopenharmony_ci f->wend = f->buf + f->buf_size; 459570af302Sopenharmony_ci } 460570af302Sopenharmony_ci#endif 461570af302Sopenharmony_ci for (;;) { 462570af302Sopenharmony_ci /* This error is only specified for snprintf, but since it's 463570af302Sopenharmony_ci * unspecified for other forms, do the same. Stop immediately 464570af302Sopenharmony_ci * on overflow; otherwise %n could produce wrong results. */ 465570af302Sopenharmony_ci if (l > INT_MAX - cnt) goto overflow; 466570af302Sopenharmony_ci 467570af302Sopenharmony_ci /* Update output count, end loop when fmt is exhausted */ 468570af302Sopenharmony_ci cnt += l; 469570af302Sopenharmony_ci if (!*s) break; 470570af302Sopenharmony_ci 471570af302Sopenharmony_ci /* Handle literal text and %% format specifiers */ 472570af302Sopenharmony_ci for (a=s; *s && *s!='%'; s++); 473570af302Sopenharmony_ci for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2); 474570af302Sopenharmony_ci if (z-a > INT_MAX-cnt) goto overflow; 475570af302Sopenharmony_ci l = z-a; 476570af302Sopenharmony_ci if (f) out(f, a, l); 477570af302Sopenharmony_ci if (l) continue; 478570af302Sopenharmony_ci 479570af302Sopenharmony_ci if (isdigit(s[1]) && s[2]=='$') { 480570af302Sopenharmony_ci l10n=1; 481570af302Sopenharmony_ci argpos = s[1]-'0'; 482570af302Sopenharmony_ci s+=3; 483570af302Sopenharmony_ci } else { 484570af302Sopenharmony_ci argpos = -1; 485570af302Sopenharmony_ci s++; 486570af302Sopenharmony_ci } 487570af302Sopenharmony_ci 488570af302Sopenharmony_ci /* Read modifier flags */ 489570af302Sopenharmony_ci for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<(*s-' '))); s++) 490570af302Sopenharmony_ci fl |= 1U<<(*s-' '); 491570af302Sopenharmony_ci 492570af302Sopenharmony_ci /* Read field width */ 493570af302Sopenharmony_ci if (*s=='*') { 494570af302Sopenharmony_ci if (isdigit(s[1]) && s[2]=='$') { 495570af302Sopenharmony_ci l10n=1; 496570af302Sopenharmony_ci nl_type[s[1]-'0'] = INT; 497570af302Sopenharmony_ci w = nl_arg[s[1]-'0'].i; 498570af302Sopenharmony_ci s+=3; 499570af302Sopenharmony_ci } else if (!l10n) { 500570af302Sopenharmony_ci w = f ? va_arg(*ap, int) : 0; 501570af302Sopenharmony_ci s++; 502570af302Sopenharmony_ci } else goto inval; 503570af302Sopenharmony_ci if (w<0) fl|=LEFT_ADJ, w=-w; 504570af302Sopenharmony_ci } else if ((w=getint(&s))<0) goto overflow; 505570af302Sopenharmony_ci 506570af302Sopenharmony_ci /* Read precision */ 507570af302Sopenharmony_ci if (*s=='.' && s[1]=='*') { 508570af302Sopenharmony_ci if (isdigit(s[2]) && s[3]=='$') { 509570af302Sopenharmony_ci nl_type[s[2]-'0'] = INT; 510570af302Sopenharmony_ci p = nl_arg[s[2]-'0'].i; 511570af302Sopenharmony_ci s+=4; 512570af302Sopenharmony_ci } else if (!l10n) { 513570af302Sopenharmony_ci p = f ? va_arg(*ap, int) : 0; 514570af302Sopenharmony_ci s+=2; 515570af302Sopenharmony_ci } else goto inval; 516570af302Sopenharmony_ci xp = (p>=0); 517570af302Sopenharmony_ci } else if (*s=='.') { 518570af302Sopenharmony_ci s++; 519570af302Sopenharmony_ci p = getint(&s); 520570af302Sopenharmony_ci xp = 1; 521570af302Sopenharmony_ci } else { 522570af302Sopenharmony_ci p = -1; 523570af302Sopenharmony_ci xp = 0; 524570af302Sopenharmony_ci } 525570af302Sopenharmony_ci 526570af302Sopenharmony_ci /* Format specifier state machine */ 527570af302Sopenharmony_ci st=0; 528570af302Sopenharmony_ci do { 529570af302Sopenharmony_ci if (OOB(*s)) goto inval; 530570af302Sopenharmony_ci ps=st; 531570af302Sopenharmony_ci st=states[st]S(*s++); 532570af302Sopenharmony_ci } while (st-1<STOP); 533570af302Sopenharmony_ci if (!st) goto inval; 534570af302Sopenharmony_ci 535570af302Sopenharmony_ci /* Check validity of argument type (nl/normal) */ 536570af302Sopenharmony_ci if (st==NOARG) { 537570af302Sopenharmony_ci if (argpos>=0) goto inval; 538570af302Sopenharmony_ci } else { 539570af302Sopenharmony_ci if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; 540570af302Sopenharmony_ci else if (f) pop_arg(&arg, st, ap); 541570af302Sopenharmony_ci else return 0; 542570af302Sopenharmony_ci } 543570af302Sopenharmony_ci 544570af302Sopenharmony_ci if (!f) continue; 545570af302Sopenharmony_ci 546570af302Sopenharmony_ci z = buf + sizeof(buf); 547570af302Sopenharmony_ci prefix = "-+ 0X0x"; 548570af302Sopenharmony_ci pl = 0; 549570af302Sopenharmony_ci t = s[-1]; 550570af302Sopenharmony_ci 551570af302Sopenharmony_ci /* Transform ls,lc -> S,C */ 552570af302Sopenharmony_ci if (ps && (t&15)==3) t&=~32; 553570af302Sopenharmony_ci 554570af302Sopenharmony_ci /* - and 0 flags are mutually exclusive */ 555570af302Sopenharmony_ci if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; 556570af302Sopenharmony_ci 557570af302Sopenharmony_ci switch(t) { 558570af302Sopenharmony_ci case 'n': 559570af302Sopenharmony_ci switch(ps) { 560570af302Sopenharmony_ci case BARE: *(int *)arg.p = cnt; break; 561570af302Sopenharmony_ci case LPRE: *(long *)arg.p = cnt; break; 562570af302Sopenharmony_ci case LLPRE: *(long long *)arg.p = cnt; break; 563570af302Sopenharmony_ci case HPRE: *(unsigned short *)arg.p = cnt; break; 564570af302Sopenharmony_ci case HHPRE: *(unsigned char *)arg.p = cnt; break; 565570af302Sopenharmony_ci case ZTPRE: *(size_t *)arg.p = cnt; break; 566570af302Sopenharmony_ci case JPRE: *(uintmax_t *)arg.p = cnt; break; 567570af302Sopenharmony_ci } 568570af302Sopenharmony_ci continue; 569570af302Sopenharmony_ci case 'p': 570570af302Sopenharmony_ci p = MAX(p, 2*sizeof(void*)); 571570af302Sopenharmony_ci t = 'x'; 572570af302Sopenharmony_ci fl |= ALT_FORM; 573570af302Sopenharmony_ci case 'x': case 'X': 574570af302Sopenharmony_ci a = fmt_x(arg.i, z, t&32); 575570af302Sopenharmony_ci if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2; 576570af302Sopenharmony_ci if (0) { 577570af302Sopenharmony_ci case 'o': 578570af302Sopenharmony_ci a = fmt_o(arg.i, z); 579570af302Sopenharmony_ci if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1; 580570af302Sopenharmony_ci } if (0) { 581570af302Sopenharmony_ci case 'd': case 'i': 582570af302Sopenharmony_ci pl=1; 583570af302Sopenharmony_ci if (arg.i>INTMAX_MAX) { 584570af302Sopenharmony_ci arg.i=-arg.i; 585570af302Sopenharmony_ci } else if (fl & MARK_POS) { 586570af302Sopenharmony_ci prefix++; 587570af302Sopenharmony_ci } else if (fl & PAD_POS) { 588570af302Sopenharmony_ci prefix+=2; 589570af302Sopenharmony_ci } else pl=0; 590570af302Sopenharmony_ci case 'u': 591570af302Sopenharmony_ci a = fmt_u(arg.i, z); 592570af302Sopenharmony_ci } 593570af302Sopenharmony_ci if (xp && p<0) goto overflow; 594570af302Sopenharmony_ci if (xp) fl &= ~ZERO_PAD; 595570af302Sopenharmony_ci if (!arg.i && !p) { 596570af302Sopenharmony_ci a=z; 597570af302Sopenharmony_ci break; 598570af302Sopenharmony_ci } 599570af302Sopenharmony_ci p = MAX(p, z-a + !arg.i); 600570af302Sopenharmony_ci break; 601570af302Sopenharmony_ci case 'c': 602570af302Sopenharmony_ci *(a=z-(p=1))=arg.i; 603570af302Sopenharmony_ci fl &= ~ZERO_PAD; 604570af302Sopenharmony_ci break; 605570af302Sopenharmony_ci case 'm': 606570af302Sopenharmony_ci if (1) a = strerror(errno); else 607570af302Sopenharmony_ci case 's': 608570af302Sopenharmony_ci a = arg.p ? arg.p : "(null)"; 609570af302Sopenharmony_ci z = a + strnlen(a, p<0 ? INT_MAX : p); 610570af302Sopenharmony_ci if (p<0 && *z) goto overflow; 611570af302Sopenharmony_ci p = z-a; 612570af302Sopenharmony_ci fl &= ~ZERO_PAD; 613570af302Sopenharmony_ci break; 614570af302Sopenharmony_ci case 'C': 615570af302Sopenharmony_ci wc[0] = arg.i; 616570af302Sopenharmony_ci wc[1] = 0; 617570af302Sopenharmony_ci arg.p = wc; 618570af302Sopenharmony_ci p = -1; 619570af302Sopenharmony_ci case 'S': 620570af302Sopenharmony_ci ws = arg.p; 621570af302Sopenharmony_ci for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l); 622570af302Sopenharmony_ci if (l<0) return -1; 623570af302Sopenharmony_ci if (i > INT_MAX) goto overflow; 624570af302Sopenharmony_ci p = i; 625570af302Sopenharmony_ci pad(f, ' ', w, p, fl); 626570af302Sopenharmony_ci ws = arg.p; 627570af302Sopenharmony_ci for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l) 628570af302Sopenharmony_ci out(f, mb, l); 629570af302Sopenharmony_ci pad(f, ' ', w, p, fl^LEFT_ADJ); 630570af302Sopenharmony_ci l = w>p ? w : p; 631570af302Sopenharmony_ci continue; 632570af302Sopenharmony_ci case 'e': case 'f': case 'g': case 'a': 633570af302Sopenharmony_ci case 'E': case 'F': case 'G': case 'A': 634570af302Sopenharmony_ci if (xp && p<0) goto overflow; 635570af302Sopenharmony_ci l = fmt_fp(f, arg.f, w, p, fl, t); 636570af302Sopenharmony_ci if (l<0) goto overflow; 637570af302Sopenharmony_ci continue; 638570af302Sopenharmony_ci } 639570af302Sopenharmony_ci 640570af302Sopenharmony_ci if (p < z-a) p = z-a; 641570af302Sopenharmony_ci if (p > INT_MAX-pl) goto overflow; 642570af302Sopenharmony_ci if (w < pl+p) w = pl+p; 643570af302Sopenharmony_ci if (w > INT_MAX-cnt) goto overflow; 644570af302Sopenharmony_ci 645570af302Sopenharmony_ci pad(f, ' ', w, pl+p, fl); 646570af302Sopenharmony_ci out(f, prefix, pl); 647570af302Sopenharmony_ci pad(f, '0', w, pl+p, fl^ZERO_PAD); 648570af302Sopenharmony_ci pad(f, '0', p, z-a, 0); 649570af302Sopenharmony_ci out(f, a, z-a); 650570af302Sopenharmony_ci pad(f, ' ', w, pl+p, fl^LEFT_ADJ); 651570af302Sopenharmony_ci 652570af302Sopenharmony_ci l = w; 653570af302Sopenharmony_ci } 654570af302Sopenharmony_ci 655570af302Sopenharmony_ci if (f) return cnt; 656570af302Sopenharmony_ci if (!l10n) return 0; 657570af302Sopenharmony_ci 658570af302Sopenharmony_ci for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) 659570af302Sopenharmony_ci pop_arg(nl_arg+i, nl_type[i], ap); 660570af302Sopenharmony_ci for (; i<=NL_ARGMAX && !nl_type[i]; i++); 661570af302Sopenharmony_ci if (i<=NL_ARGMAX) goto inval; 662570af302Sopenharmony_ci return 1; 663570af302Sopenharmony_ci 664570af302Sopenharmony_ciinval: 665570af302Sopenharmony_ci errno = EINVAL; 666570af302Sopenharmony_ci return -1; 667570af302Sopenharmony_cioverflow: 668570af302Sopenharmony_ci errno = EOVERFLOW; 669570af302Sopenharmony_ci return -1; 670570af302Sopenharmony_ci} 671570af302Sopenharmony_ci 672570af302Sopenharmony_ciint vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) 673570af302Sopenharmony_ci{ 674570af302Sopenharmony_ci va_list ap2; 675570af302Sopenharmony_ci int nl_type[NL_ARGMAX+1] = {0}; 676570af302Sopenharmony_ci union arg nl_arg[NL_ARGMAX+1]; 677570af302Sopenharmony_ci unsigned char internal_buf[80], *saved_buf = 0; 678570af302Sopenharmony_ci int olderr; 679570af302Sopenharmony_ci int ret; 680570af302Sopenharmony_ci 681570af302Sopenharmony_ci /* the copy allows passing va_list* even if va_list is an array */ 682570af302Sopenharmony_ci va_copy(ap2, ap); 683570af302Sopenharmony_ci if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { 684570af302Sopenharmony_ci va_end(ap2); 685570af302Sopenharmony_ci return -1; 686570af302Sopenharmony_ci } 687570af302Sopenharmony_ci 688570af302Sopenharmony_ci FLOCK(f); 689570af302Sopenharmony_ci olderr = f->flags & F_ERR; 690570af302Sopenharmony_ci if (f->mode < 1) f->flags &= ~F_ERR; 691570af302Sopenharmony_ci if (!f->buf_size) { 692570af302Sopenharmony_ci saved_buf = f->buf; 693570af302Sopenharmony_ci f->buf = internal_buf; 694570af302Sopenharmony_ci f->buf_size = sizeof internal_buf; 695570af302Sopenharmony_ci f->wpos = f->wbase = f->wend = 0; 696570af302Sopenharmony_ci } 697570af302Sopenharmony_ci if (!f->wend && __towrite(f)) ret = -1; 698570af302Sopenharmony_ci else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type); 699570af302Sopenharmony_ci if (saved_buf) { 700570af302Sopenharmony_ci f->write(f, 0, 0); 701570af302Sopenharmony_ci if (!f->wpos) ret = -1; 702570af302Sopenharmony_ci f->buf = saved_buf; 703570af302Sopenharmony_ci f->buf_size = 0; 704570af302Sopenharmony_ci f->wpos = f->wbase = f->wend = 0; 705570af302Sopenharmony_ci } 706570af302Sopenharmony_ci if (f->flags & F_ERR) ret = -1; 707570af302Sopenharmony_ci f->flags |= olderr; 708570af302Sopenharmony_ci FUNLOCK(f); 709570af302Sopenharmony_ci va_end(ap2); 710570af302Sopenharmony_ci return ret; 711570af302Sopenharmony_ci} 712