1 #include "stdio_impl.h"
10 /* Convenient bit representation for modifier flags, which all fall
11 * within 31 codepoints of the space character. */
13 #define ALT_FORM (1U<<'#'-' ')
14 #define ZERO_PAD (1U<<'0'-' ')
15 #define LEFT_ADJ (1U<<'-'-' ')
16 #define PAD_POS (1U<<' '-' ')
17 #define MARK_POS (1U<<'+'-' ')
18 #define GROUPED (1U<<'\''-' ')
20 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
22 #if UINT_MAX == ULONG_MAX
26 #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
30 /* State machine to accept length modifiers + conversion specifiers.
31 * Result is 0 on failure, or an argument type to pop on success. */
34 BARE
, LPRE
, LLPRE
, HPRE
, HHPRE
, BIGLPRE
,
37 PTR
, INT
, UINT
, ULLONG
,
44 SHORT
, USHORT
, CHAR
, UCHAR
,
46 LLONG
, SIZET
, IMAX
, UMAX
, PDIFF
, UIPTR
,
60 #define S(x) [(x)-'A']
62 static const unsigned char states
[]['z'-'A'+1] = {
64 S('d') = INT
, S('i') = INT
,
65 S('o') = UINT
, S('u') = UINT
, S('x') = UINT
, S('X') = UINT
,
66 S('e') = DBL
, S('f') = DBL
, S('g') = DBL
, S('a') = DBL
,
67 S('E') = DBL
, S('F') = DBL
, S('G') = DBL
, S('A') = DBL
,
68 S('c') = CHAR
, S('C') = INT
,
69 S('s') = PTR
, S('S') = PTR
, S('p') = UIPTR
, S('n') = PTR
,
71 S('l') = LPRE
, S('h') = HPRE
, S('L') = BIGLPRE
,
72 S('z') = ZTPRE
, S('j') = JPRE
, S('t') = ZTPRE
,
73 }, { /* 1: l-prefixed */
74 S('d') = LONG
, S('i') = LONG
,
75 S('o') = ULONG
, S('u') = ULONG
, S('x') = ULONG
, S('X') = ULONG
,
76 S('c') = INT
, S('s') = PTR
, S('n') = PTR
,
78 }, { /* 2: ll-prefixed */
79 S('d') = LLONG
, S('i') = LLONG
,
80 S('o') = ULLONG
, S('u') = ULLONG
,
81 S('x') = ULLONG
, S('X') = ULLONG
,
83 }, { /* 3: h-prefixed */
84 S('d') = SHORT
, S('i') = SHORT
,
85 S('o') = USHORT
, S('u') = USHORT
,
86 S('x') = USHORT
, S('X') = USHORT
,
89 }, { /* 4: hh-prefixed */
90 S('d') = CHAR
, S('i') = CHAR
,
91 S('o') = UCHAR
, S('u') = UCHAR
,
92 S('x') = UCHAR
, S('X') = UCHAR
,
94 }, { /* 5: L-prefixed */
95 S('e') = LDBL
, S('f') = LDBL
, S('g') = LDBL
, S('a') = LDBL
,
96 S('E') = LDBL
, S('F') = LDBL
, S('G') = LDBL
, S('A') = LDBL
,
98 }, { /* 6: z- or t-prefixed (assumed to be same size) */
99 S('d') = PDIFF
, S('i') = PDIFF
,
100 S('o') = SIZET
, S('u') = SIZET
,
101 S('x') = SIZET
, S('X') = SIZET
,
103 }, { /* 7: j-prefixed */
104 S('d') = IMAX
, S('i') = IMAX
,
105 S('o') = UMAX
, S('u') = UMAX
,
106 S('x') = UMAX
, S('X') = UMAX
,
111 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
120 static void pop_arg(union arg
*arg
, int type
, va_list *ap
)
122 /* Give the compiler a hint for optimizing the switch. */
123 if ((unsigned)type
> MAXSTATE
) return;
125 case PTR
: arg
->p
= va_arg(*ap
, void *);
126 break; case INT
: arg
->i
= va_arg(*ap
, int);
127 break; case UINT
: arg
->i
= va_arg(*ap
, unsigned int);
129 break; case LONG
: arg
->i
= va_arg(*ap
, long);
130 break; case ULONG
: arg
->i
= va_arg(*ap
, unsigned long);
132 break; case ULLONG
: arg
->i
= va_arg(*ap
, unsigned long long);
133 break; case SHORT
: arg
->i
= (short)va_arg(*ap
, int);
134 break; case USHORT
: arg
->i
= (unsigned short)va_arg(*ap
, int);
135 break; case CHAR
: arg
->i
= (signed char)va_arg(*ap
, int);
136 break; case UCHAR
: arg
->i
= (unsigned char)va_arg(*ap
, int);
138 break; case LLONG
: arg
->i
= va_arg(*ap
, long long);
139 break; case SIZET
: arg
->i
= va_arg(*ap
, size_t);
140 break; case IMAX
: arg
->i
= va_arg(*ap
, intmax_t);
141 break; case UMAX
: arg
->i
= va_arg(*ap
, uintmax_t);
142 break; case PDIFF
: arg
->i
= va_arg(*ap
, ptrdiff_t);
143 break; case UIPTR
: arg
->i
= (uintptr_t)va_arg(*ap
, void *);
145 break; case DBL
: arg
->f
= va_arg(*ap
, double);
146 break; case LDBL
: arg
->f
= va_arg(*ap
, long double);
150 static void out(FILE *f
, const wchar_t *s
, size_t l
)
152 while (l
-- && !(f
->flags
& F_ERR
)) fputwc(*s
++, f
);
155 static int getint(wchar_t **s
) {
157 for (i
=0; iswdigit(**s
); (*s
)++) {
158 if (i
> INT_MAX
/10U || **s
-'0' > INT_MAX
-10*i
) i
= -1;
159 else i
= 10*i
+ (**s
-'0');
164 static const char sizeprefix
['y'-'a'] = {
165 ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
166 ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
170 static int wprintf_core(FILE *f
, const wchar_t *fmt
, va_list *ap
, union arg
*nl_arg
, int *nl_type
)
172 wchar_t *a
, *z
, *s
=(wchar_t *)fmt
;
186 /* This error is only specified for snprintf, but since it's
187 * unspecified for other forms, do the same. Stop immediately
188 * on overflow; otherwise %n could produce wrong results. */
189 if (l
> INT_MAX
- cnt
) goto overflow
;
191 /* Update output count, end loop when fmt is exhausted */
195 /* Handle literal text and %% format specifiers */
196 for (a
=s
; *s
&& *s
!='%'; s
++);
197 for (z
=s
; s
[0]=='%' && s
[1]=='%'; z
++, s
+=2);
198 if (z
-a
> INT_MAX
-cnt
) goto overflow
;
203 if (iswdigit(s
[1]) && s
[2]=='$') {
212 /* Read modifier flags */
213 for (fl
=0; (unsigned)*s
-' '<32 && (FLAGMASK
&(1U<<*s
-' ')); s
++)
216 /* Read field width */
218 if (iswdigit(s
[1]) && s
[2]=='$') {
220 nl_type
[s
[1]-'0'] = INT
;
221 w
= nl_arg
[s
[1]-'0'].i
;
224 w
= f
? va_arg(*ap
, int) : 0;
227 if (w
<0) fl
|=LEFT_ADJ
, w
=-w
;
228 } else if ((w
=getint(&s
))<0) goto overflow
;
231 if (*s
=='.' && s
[1]=='*') {
232 if (isdigit(s
[2]) && s
[3]=='$') {
233 nl_type
[s
[2]-'0'] = INT
;
234 p
= nl_arg
[s
[2]-'0'].i
;
237 p
= f
? va_arg(*ap
, int) : 0;
241 } else if (*s
=='.') {
250 /* Format specifier state machine */
253 if (OOB(*s
)) goto inval
;
255 st
=states
[st
]S(*s
++);
259 /* Check validity of argument type (nl/normal) */
261 if (argpos
>=0) goto inval
;
263 if (argpos
>=0) nl_type
[argpos
]=st
, arg
=nl_arg
[argpos
];
264 else if (f
) pop_arg(&arg
, st
, ap
);
270 if (ps
&& (t
&15)==3) t
&=~32;
275 case BARE
: *(int *)arg
.p
= cnt
; break;
276 case LPRE
: *(long *)arg
.p
= cnt
; break;
277 case LLPRE
: *(long long *)arg
.p
= cnt
; break;
278 case HPRE
: *(unsigned short *)arg
.p
= cnt
; break;
279 case HHPRE
: *(unsigned char *)arg
.p
= cnt
; break;
280 case ZTPRE
: *(size_t *)arg
.p
= cnt
; break;
281 case JPRE
: *(uintmax_t *)arg
.p
= cnt
; break;
285 fputwc(btowc(arg
.i
), f
);
294 z
= a
+ wcsnlen(a
, p
<0 ? INT_MAX
: p
);
295 if (p
<0 && *z
) goto overflow
;
298 if (!(fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
300 if ((fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
304 arg
.p
= strerror(errno
);
306 if (!arg
.p
) arg
.p
= "(null)";
308 for (i
=l
=0; l
<(p
<0?INT_MAX
:p
) && (i
=mbtowc(&wc
, bs
, MB_LEN_MAX
))>0; bs
+=i
, l
++);
310 if (p
<0 && *bs
) goto overflow
;
313 if (!(fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
316 i
=mbtowc(&wc
, bs
, MB_LEN_MAX
);
320 if ((fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
325 if (xp
&& p
<0) goto overflow
;
326 snprintf(charfmt
, sizeof charfmt
, "%%%s%s%s%s%s*.*%c%c",
327 "#"+!(fl
& ALT_FORM
),
328 "+"+!(fl
& MARK_POS
),
329 "-"+!(fl
& LEFT_ADJ
),
331 "0"+!(fl
& ZERO_PAD
),
332 sizeprefix
[(t
|32)-'a'], t
);
335 case 'a': case 'e': case 'f': case 'g':
336 l
= fprintf(f
, charfmt
, w
, p
, arg
.f
);
338 case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
339 l
= fprintf(f
, charfmt
, w
, p
, arg
.i
);
347 for (i
=1; i
<=NL_ARGMAX
&& nl_type
[i
]; i
++)
348 pop_arg(nl_arg
+i
, nl_type
[i
], ap
);
349 for (; i
<=NL_ARGMAX
&& !nl_type
[i
]; i
++);
350 if (i
<=NL_ARGMAX
) return -1;
361 int vfwprintf(FILE *restrict f
, const wchar_t *restrict fmt
, va_list ap
)
364 int nl_type
[NL_ARGMAX
] = {0};
365 union arg nl_arg
[NL_ARGMAX
];
369 /* the copy allows passing va_list* even if va_list is an array */
371 if (wprintf_core(0, fmt
, &ap2
, nl_arg
, nl_type
) < 0) {
378 olderr
= f
->flags
& F_ERR
;
380 ret
= wprintf_core(f
, fmt
, &ap2
, nl_arg
, nl_type
);
381 if (f
->flags
& F_ERR
) ret
= -1;