1 #include "stdio_impl.h"
12 /* Convenient bit representation for modifier flags, which all fall
13 * within 31 codepoints of the space character. */
15 #define ALT_FORM (1U<<'#'-' ')
16 #define ZERO_PAD (1U<<'0'-' ')
17 #define LEFT_ADJ (1U<<'-'-' ')
18 #define PAD_POS (1U<<' '-' ')
19 #define MARK_POS (1U<<'+'-' ')
20 #define GROUPED (1U<<'\''-' ')
22 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
24 /* State machine to accept length modifiers + conversion specifiers.
25 * Result is 0 on failure, or an argument type to pop on success. */
28 BARE
, LPRE
, LLPRE
, HPRE
, HHPRE
, BIGLPRE
,
31 PTR
, INT
, UINT
, ULLONG
,
33 SHORT
, USHORT
, CHAR
, UCHAR
,
34 LLONG
, SIZET
, IMAX
, UMAX
, PDIFF
, UIPTR
,
40 #define S(x) [(x)-'A']
42 static const unsigned char states
[]['z'-'A'+1] = {
44 S('d') = INT
, S('i') = INT
,
45 S('o') = UINT
, S('u') = UINT
, S('x') = UINT
, S('X') = UINT
,
46 S('e') = DBL
, S('f') = DBL
, S('g') = DBL
, S('a') = DBL
,
47 S('E') = DBL
, S('F') = DBL
, S('G') = DBL
, S('A') = DBL
,
48 S('c') = CHAR
, S('C') = INT
,
49 S('s') = PTR
, S('S') = PTR
, S('p') = UIPTR
, S('n') = PTR
,
51 S('l') = LPRE
, S('h') = HPRE
, S('L') = BIGLPRE
,
52 S('z') = ZTPRE
, S('j') = JPRE
, S('t') = ZTPRE
,
53 }, { /* 1: l-prefixed */
54 S('d') = LONG
, S('i') = LONG
,
55 S('o') = ULONG
, S('u') = ULONG
, S('x') = ULONG
, S('X') = ULONG
,
56 S('e') = DBL
, S('f') = DBL
, S('g') = DBL
, S('a') = DBL
,
57 S('E') = DBL
, S('F') = DBL
, S('G') = DBL
, S('A') = DBL
,
58 S('c') = INT
, S('s') = PTR
, S('n') = PTR
,
60 }, { /* 2: ll-prefixed */
61 S('d') = LLONG
, S('i') = LLONG
,
62 S('o') = ULLONG
, S('u') = ULLONG
,
63 S('x') = ULLONG
, S('X') = ULLONG
,
65 }, { /* 3: h-prefixed */
66 S('d') = SHORT
, S('i') = SHORT
,
67 S('o') = USHORT
, S('u') = USHORT
,
68 S('x') = USHORT
, S('X') = USHORT
,
71 }, { /* 4: hh-prefixed */
72 S('d') = CHAR
, S('i') = CHAR
,
73 S('o') = UCHAR
, S('u') = UCHAR
,
74 S('x') = UCHAR
, S('X') = UCHAR
,
76 }, { /* 5: L-prefixed */
77 S('e') = LDBL
, S('f') = LDBL
, S('g') = LDBL
, S('a') = LDBL
,
78 S('E') = LDBL
, S('F') = LDBL
, S('G') = LDBL
, S('A') = LDBL
,
80 }, { /* 6: z- or t-prefixed (assumed to be same size) */
81 S('d') = PDIFF
, S('i') = PDIFF
,
82 S('o') = SIZET
, S('u') = SIZET
,
83 S('x') = SIZET
, S('X') = SIZET
,
85 }, { /* 7: j-prefixed */
86 S('d') = IMAX
, S('i') = IMAX
,
87 S('o') = UMAX
, S('u') = UMAX
,
88 S('x') = UMAX
, S('X') = UMAX
,
93 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
102 static void pop_arg(union arg
*arg
, int type
, va_list *ap
)
105 case PTR
: arg
->p
= va_arg(*ap
, void *);
106 break; case INT
: arg
->i
= va_arg(*ap
, int);
107 break; case UINT
: arg
->i
= va_arg(*ap
, unsigned int);
108 break; case LONG
: arg
->i
= va_arg(*ap
, long);
109 break; case ULONG
: arg
->i
= va_arg(*ap
, unsigned long);
110 break; case ULLONG
: arg
->i
= va_arg(*ap
, unsigned long long);
111 break; case SHORT
: arg
->i
= (short)va_arg(*ap
, int);
112 break; case USHORT
: arg
->i
= (unsigned short)va_arg(*ap
, int);
113 break; case CHAR
: arg
->i
= (signed char)va_arg(*ap
, int);
114 break; case UCHAR
: arg
->i
= (unsigned char)va_arg(*ap
, int);
115 break; case LLONG
: arg
->i
= va_arg(*ap
, long long);
116 break; case SIZET
: arg
->i
= va_arg(*ap
, size_t);
117 break; case IMAX
: arg
->i
= va_arg(*ap
, intmax_t);
118 break; case UMAX
: arg
->i
= va_arg(*ap
, uintmax_t);
119 break; case PDIFF
: arg
->i
= va_arg(*ap
, ptrdiff_t);
120 break; case UIPTR
: arg
->i
= (uintptr_t)va_arg(*ap
, void *);
121 break; case DBL
: arg
->f
= va_arg(*ap
, double);
122 break; case LDBL
: arg
->f
= va_arg(*ap
, long double);
126 static void out(FILE *f
, const wchar_t *s
, size_t l
)
128 while (l
-- && !(f
->flags
& F_ERR
)) fputwc(*s
++, f
);
131 static int getint(wchar_t **s
) {
133 for (i
=0; iswdigit(**s
); (*s
)++) {
134 if (i
> INT_MAX
/10U || **s
-'0' > INT_MAX
-10*i
) i
= -1;
135 else i
= 10*i
+ (**s
-'0');
140 static const char sizeprefix
['y'-'a'] = {
141 ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
142 ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
146 static int wprintf_core(FILE *f
, const wchar_t *fmt
, va_list *ap
, union arg
*nl_arg
, int *nl_type
)
148 wchar_t *a
, *z
, *s
=(wchar_t *)fmt
;
162 /* This error is only specified for snprintf, but since it's
163 * unspecified for other forms, do the same. Stop immediately
164 * on overflow; otherwise %n could produce wrong results. */
165 if (l
> INT_MAX
- cnt
) goto overflow
;
167 /* Update output count, end loop when fmt is exhausted */
171 /* Handle literal text and %% format specifiers */
172 for (a
=s
; *s
&& *s
!='%'; s
++);
173 for (z
=s
; s
[0]=='%' && s
[1]=='%'; z
++, s
+=2);
174 if (z
-a
> INT_MAX
-cnt
) goto overflow
;
179 if (iswdigit(s
[1]) && s
[2]=='$') {
188 /* Read modifier flags */
189 for (fl
=0; (unsigned)*s
-' '<32 && (FLAGMASK
&(1U<<*s
-' ')); s
++)
192 /* Read field width */
194 if (iswdigit(s
[1]) && s
[2]=='$') {
196 nl_type
[s
[1]-'0'] = INT
;
197 w
= nl_arg
[s
[1]-'0'].i
;
200 w
= f
? va_arg(*ap
, int) : 0;
203 if (w
<0) fl
|=LEFT_ADJ
, w
=-w
;
204 } else if ((w
=getint(&s
))<0) goto overflow
;
207 if (*s
=='.' && s
[1]=='*') {
208 if (isdigit(s
[2]) && s
[3]=='$') {
209 nl_type
[s
[2]-'0'] = INT
;
210 p
= nl_arg
[s
[2]-'0'].i
;
213 p
= f
? va_arg(*ap
, int) : 0;
217 } else if (*s
=='.') {
226 /* Format specifier state machine */
229 if (OOB(*s
)) goto inval
;
231 st
=states
[st
]S(*s
++);
235 /* Check validity of argument type (nl/normal) */
237 if (argpos
>=0) goto inval
;
239 if (argpos
>=0) nl_type
[argpos
]=st
, arg
=nl_arg
[argpos
];
240 else if (f
) pop_arg(&arg
, st
, ap
);
246 if (ps
&& (t
&15)==3) t
&=~32;
251 case BARE
: *(int *)arg
.p
= cnt
; break;
252 case LPRE
: *(long *)arg
.p
= cnt
; break;
253 case LLPRE
: *(long long *)arg
.p
= cnt
; break;
254 case HPRE
: *(unsigned short *)arg
.p
= cnt
; break;
255 case HHPRE
: *(unsigned char *)arg
.p
= cnt
; break;
256 case ZTPRE
: *(size_t *)arg
.p
= cnt
; break;
257 case JPRE
: *(uintmax_t *)arg
.p
= cnt
; break;
262 if (w
>1 && !(fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-1, "");
263 fputwc(btowc(arg
.i
), f
);
264 if (w
>1 && (fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-1, "");
273 z
= a
+ wcsnlen(a
, p
<0 ? INT_MAX
: p
);
274 if (p
<0 && *z
) goto overflow
;
277 if (!(fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
279 if ((fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
283 arg
.p
= strerror(errno
);
285 if (!arg
.p
) arg
.p
= "(null)";
287 for (i
=l
=0; l
<(p
<0?INT_MAX
:p
) && (i
=mbtowc(&wc
, bs
, MB_LEN_MAX
))>0; bs
+=i
, l
++);
289 if (p
<0 && *bs
) goto overflow
;
292 if (!(fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
295 i
=mbtowc(&wc
, bs
, MB_LEN_MAX
);
299 if ((fl
&LEFT_ADJ
)) fprintf(f
, "%*s", w
-p
, "");
304 if (xp
&& p
<0) goto overflow
;
305 snprintf(charfmt
, sizeof charfmt
, "%%%s%s%s%s%s*.*%c%c",
306 "#"+!(fl
& ALT_FORM
),
307 "+"+!(fl
& MARK_POS
),
308 "-"+!(fl
& LEFT_ADJ
),
310 "0"+!(fl
& ZERO_PAD
),
311 sizeprefix
[(t
|32)-'a'], t
);
314 case 'a': case 'e': case 'f': case 'g':
315 l
= fprintf(f
, charfmt
, w
, p
, arg
.f
);
317 case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
318 l
= fprintf(f
, charfmt
, w
, p
, arg
.i
);
326 for (i
=1; i
<=NL_ARGMAX
&& nl_type
[i
]; i
++)
327 pop_arg(nl_arg
+i
, nl_type
[i
], ap
);
328 for (; i
<=NL_ARGMAX
&& !nl_type
[i
]; i
++);
329 if (i
<=NL_ARGMAX
) return -1;
340 int vfwprintf(FILE *restrict f
, const wchar_t *restrict fmt
, va_list ap
)
343 int nl_type
[NL_ARGMAX
] = {0};
344 union arg nl_arg
[NL_ARGMAX
];
348 /* the copy allows passing va_list* even if va_list is an array */
350 if (wprintf_core(0, fmt
, &ap2
, nl_arg
, nl_type
) < 0) {
357 olderr
= f
->flags
& F_ERR
;
359 ret
= wprintf_core(f
, fmt
, &ap2
, nl_arg
, nl_type
);
360 if (f
->flags
& F_ERR
) ret
= -1;