OLD | NEW |
1 #include "stdio_impl.h" | 1 #include "stdio_impl.h" |
2 #include <errno.h> | 2 #include <errno.h> |
3 #include <ctype.h> | 3 #include <ctype.h> |
4 #include <limits.h> | 4 #include <limits.h> |
5 #include <string.h> | 5 #include <string.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <wchar.h> | 7 #include <wchar.h> |
8 #include <inttypes.h> | 8 #include <inttypes.h> |
9 | 9 |
10 /* Convenient bit representation for modifier flags, which all fall | 10 /* Convenient bit representation for modifier flags, which all fall |
11 * within 31 codepoints of the space character. */ | 11 * within 31 codepoints of the space character. */ |
12 | 12 |
13 #define ALT_FORM (1U<<('#'-' ')) | 13 #define ALT_FORM (1U << ('#' - ' ')) |
14 #define ZERO_PAD (1U<<('0'-' ')) | 14 #define ZERO_PAD (1U << ('0' - ' ')) |
15 #define LEFT_ADJ (1U<<('-'-' ')) | 15 #define LEFT_ADJ (1U << ('-' - ' ')) |
16 #define PAD_POS (1U<<(' '-' ')) | 16 #define PAD_POS (1U << (' ' - ' ')) |
17 #define MARK_POS (1U<<('+'-' ')) | 17 #define MARK_POS (1U << ('+' - ' ')) |
18 #define GROUPED (1U<<('\''-' ')) | 18 #define GROUPED (1U << ('\'' - ' ')) |
19 | 19 |
20 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) | 20 #define FLAGMASK (ALT_FORM | ZERO_PAD | LEFT_ADJ | PAD_POS | MARK_POS | GROUPED) |
21 | 21 |
22 #if UINT_MAX == ULONG_MAX | 22 #if UINT_MAX == ULONG_MAX |
23 #define LONG_IS_INT | 23 #define LONG_IS_INT |
24 #endif | 24 #endif |
25 | 25 |
26 #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX | 26 #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX |
27 #define ODD_TYPES | 27 #define ODD_TYPES |
28 #endif | 28 #endif |
29 | 29 |
30 /* State machine to accept length modifiers + conversion specifiers. | 30 /* State machine to accept length modifiers + conversion specifiers. |
31 * Result is 0 on failure, or an argument type to pop on success. */ | 31 * Result is 0 on failure, or an argument type to pop on success. */ |
32 | 32 |
33 enum { | 33 enum { |
34 » BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, | 34 BARE, |
35 » ZTPRE, JPRE, | 35 LPRE, |
36 » STOP, | 36 LLPRE, |
37 » PTR, INT, UINT, ULLONG, | 37 HPRE, |
| 38 HHPRE, |
| 39 BIGLPRE, |
| 40 ZTPRE, |
| 41 JPRE, |
| 42 STOP, |
| 43 PTR, |
| 44 INT, |
| 45 UINT, |
| 46 ULLONG, |
38 #ifndef LONG_IS_INT | 47 #ifndef LONG_IS_INT |
39 » LONG, ULONG, | 48 LONG, |
| 49 ULONG, |
40 #else | 50 #else |
41 #define LONG INT | 51 #define LONG INT |
42 #define ULONG UINT | 52 #define ULONG UINT |
43 #endif | 53 #endif |
44 » SHORT, USHORT, CHAR, UCHAR, | 54 SHORT, |
| 55 USHORT, |
| 56 CHAR, |
| 57 UCHAR, |
45 #ifdef ODD_TYPES | 58 #ifdef ODD_TYPES |
46 » LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, | 59 LLONG, |
| 60 SIZET, |
| 61 IMAX, |
| 62 UMAX, |
| 63 PDIFF, |
| 64 UIPTR, |
47 #else | 65 #else |
48 #define LLONG ULLONG | 66 #define LLONG ULLONG |
49 #define SIZET ULONG | 67 #define SIZET ULONG |
50 #define IMAX LLONG | 68 #define IMAX LLONG |
51 #define UMAX ULLONG | 69 #define UMAX ULLONG |
52 #define PDIFF LONG | 70 #define PDIFF LONG |
53 #define UIPTR ULONG | 71 #define UIPTR ULONG |
54 #endif | 72 #endif |
55 » DBL, LDBL, | 73 DBL, |
56 » NOARG, | 74 LDBL, |
57 » MAXSTATE | 75 NOARG, |
| 76 MAXSTATE |
58 }; | 77 }; |
59 | 78 |
60 #define S(x) [(x)-'A'] | 79 #define S(x) [(x) - 'A'] |
61 | 80 |
62 static const unsigned char states[]['z'-'A'+1] = { | 81 static const unsigned char states[]['z' - 'A' + 1] = { |
63 » { /* 0: bare types */ | 82 { |
64 » » S('d') = INT, S('i') = INT, | 83 /* 0: bare types */ |
65 » » S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, | 84 S('d') = INT, S('i') = INT, S('o') = UINT, S('u') = UINT, |
66 » » S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, | 85 S('x') = UINT, S('X') = UINT, S('e') = DBL, S('f') = DBL, |
67 » » S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, | 86 S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, |
68 » » S('c') = CHAR, S('C') = INT, | 87 S('G') = DBL, S('A') = DBL, S('c') = CHAR, S('C') = INT, |
69 » » S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, | 88 S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, |
70 » » S('m') = NOARG, | 89 S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, |
71 » » S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, | 90 S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, |
72 » » S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, | 91 }, |
73 » }, { /* 1: l-prefixed */ | 92 { |
74 » » S('d') = LONG, S('i') = LONG, | 93 /* 1: l-prefixed */ |
75 » » S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, | 94 S('d') = LONG, S('i') = LONG, S('o') = ULONG, S('u') = ULONG, |
76 » » S('c') = INT, S('s') = PTR, S('n') = PTR, | 95 S('x') = ULONG, S('X') = ULONG, S('c') = INT, S('s') = PTR, |
77 » » S('l') = LLPRE, | 96 S('n') = PTR, S('l') = LLPRE, |
78 » }, { /* 2: ll-prefixed */ | 97 }, |
79 » » S('d') = LLONG, S('i') = LLONG, | 98 { |
80 » » S('o') = ULLONG, S('u') = ULLONG, | 99 /* 2: ll-prefixed */ |
81 » » S('x') = ULLONG, S('X') = ULLONG, | 100 S('d') = LLONG, S('i') = LLONG, S('o') = ULLONG, S('u') = ULLONG, |
82 » » S('n') = PTR, | 101 S('x') = ULLONG, S('X') = ULLONG, S('n') = PTR, |
83 » }, { /* 3: h-prefixed */ | 102 }, |
84 » » S('d') = SHORT, S('i') = SHORT, | 103 { |
85 » » S('o') = USHORT, S('u') = USHORT, | 104 /* 3: h-prefixed */ |
86 » » S('x') = USHORT, S('X') = USHORT, | 105 S('d') = SHORT, S('i') = SHORT, S('o') = USHORT, S('u') = USHORT, |
87 » » S('n') = PTR, | 106 S('x') = USHORT, S('X') = USHORT, S('n') = PTR, S('h') = HHPRE, |
88 » » S('h') = HHPRE, | 107 }, |
89 » }, { /* 4: hh-prefixed */ | 108 { |
90 » » S('d') = CHAR, S('i') = CHAR, | 109 /* 4: hh-prefixed */ |
91 » » S('o') = UCHAR, S('u') = UCHAR, | 110 S('d') = CHAR, S('i') = CHAR, S('o') = UCHAR, S('u') = UCHAR, |
92 » » S('x') = UCHAR, S('X') = UCHAR, | 111 S('x') = UCHAR, S('X') = UCHAR, S('n') = PTR, |
93 » » S('n') = PTR, | 112 }, |
94 » }, { /* 5: L-prefixed */ | 113 { |
95 » » S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, | 114 /* 5: L-prefixed */ |
96 » » S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, | 115 S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, |
97 » » S('n') = PTR, | 116 S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, |
98 » }, { /* 6: z- or t-prefixed (assumed to be same size) */ | 117 S('n') = PTR, |
99 » » S('d') = PDIFF, S('i') = PDIFF, | 118 }, |
100 » » S('o') = SIZET, S('u') = SIZET, | 119 { |
101 » » S('x') = SIZET, S('X') = SIZET, | 120 /* 6: z- or t-prefixed (assumed to be same size) */ |
102 » » S('n') = PTR, | 121 S('d') = PDIFF, S('i') = PDIFF, S('o') = SIZET, S('u') = SIZET, |
103 » }, { /* 7: j-prefixed */ | 122 S('x') = SIZET, S('X') = SIZET, S('n') = PTR, |
104 » » S('d') = IMAX, S('i') = IMAX, | 123 }, |
105 » » S('o') = UMAX, S('u') = UMAX, | 124 { |
106 » » S('x') = UMAX, S('X') = UMAX, | 125 /* 7: j-prefixed */ |
107 » » S('n') = PTR, | 126 S('d') = IMAX, S('i') = IMAX, S('o') = UMAX, S('u') = UMAX, |
108 » } | 127 S('x') = UMAX, S('X') = UMAX, S('n') = PTR, |
| 128 }}; |
| 129 |
| 130 #define OOB(x) ((unsigned)(x) - 'A' > 'z' - 'A') |
| 131 |
| 132 union arg { |
| 133 uintmax_t i; |
| 134 long double f; |
| 135 void* p; |
109 }; | 136 }; |
110 | 137 |
111 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') | 138 static void pop_arg(union arg* arg, int type, va_list* ap) { |
112 | 139 /* Give the compiler a hint for optimizing the switch. */ |
113 union arg | 140 if ((unsigned)type > MAXSTATE) |
114 { | 141 return; |
115 » uintmax_t i; | 142 switch (type) { |
116 » long double f; | 143 case PTR: |
117 » void *p; | 144 arg->p = va_arg(*ap, void*); |
118 }; | 145 break; |
119 | 146 case INT: |
120 static void pop_arg(union arg *arg, int type, va_list *ap) | 147 arg->i = va_arg(*ap, int); |
121 { | 148 break; |
122 » /* Give the compiler a hint for optimizing the switch. */ | 149 case UINT: |
123 » if ((unsigned)type > MAXSTATE) return; | 150 arg->i = va_arg(*ap, unsigned int); |
124 » switch (type) { | |
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); | |
128 #ifndef LONG_IS_INT | 151 #ifndef LONG_IS_INT |
129 » break; case LONG:» arg->i = va_arg(*ap, long); | 152 break; |
130 » break; case ULONG:» arg->i = va_arg(*ap, unsigned long); | 153 case LONG: |
| 154 arg->i = va_arg(*ap, long); |
| 155 break; |
| 156 case ULONG: |
| 157 arg->i = va_arg(*ap, unsigned long); |
131 #endif | 158 #endif |
132 » break; case ULLONG:» arg->i = va_arg(*ap, unsigned long long); | 159 break; |
133 » break; case SHORT:» arg->i = (short)va_arg(*ap, int); | 160 case ULLONG: |
134 » break; case USHORT:» arg->i = (unsigned short)va_arg(*ap, int); | 161 arg->i = va_arg(*ap, unsigned long long); |
135 » break; case CHAR:» arg->i = (signed char)va_arg(*ap, int); | 162 break; |
136 » break; case UCHAR:» arg->i = (unsigned char)va_arg(*ap, int); | 163 case SHORT: |
| 164 arg->i = (short)va_arg(*ap, int); |
| 165 break; |
| 166 case USHORT: |
| 167 arg->i = (unsigned short)va_arg(*ap, int); |
| 168 break; |
| 169 case CHAR: |
| 170 arg->i = (signed char)va_arg(*ap, int); |
| 171 break; |
| 172 case UCHAR: |
| 173 arg->i = (unsigned char)va_arg(*ap, int); |
137 #ifdef ODD_TYPES | 174 #ifdef ODD_TYPES |
138 » break; case LLONG:» arg->i = va_arg(*ap, long long); | 175 break; |
139 » break; case SIZET:» arg->i = va_arg(*ap, size_t); | 176 case LLONG: |
140 » break; case IMAX:» arg->i = va_arg(*ap, intmax_t); | 177 arg->i = va_arg(*ap, long long); |
141 » break; case UMAX:» arg->i = va_arg(*ap, uintmax_t); | 178 break; |
142 » break; case PDIFF:» arg->i = va_arg(*ap, ptrdiff_t); | 179 case SIZET: |
143 » break; case UIPTR:» arg->i = (uintptr_t)va_arg(*ap, void *); | 180 arg->i = va_arg(*ap, size_t); |
| 181 break; |
| 182 case IMAX: |
| 183 arg->i = va_arg(*ap, intmax_t); |
| 184 break; |
| 185 case UMAX: |
| 186 arg->i = va_arg(*ap, uintmax_t); |
| 187 break; |
| 188 case PDIFF: |
| 189 arg->i = va_arg(*ap, ptrdiff_t); |
| 190 break; |
| 191 case UIPTR: |
| 192 arg->i = (uintptr_t)va_arg(*ap, void*); |
144 #endif | 193 #endif |
145 » break; case DBL:» arg->f = va_arg(*ap, double); | 194 break; |
146 » break; case LDBL:» arg->f = va_arg(*ap, long double); | 195 case DBL: |
147 » } | 196 arg->f = va_arg(*ap, double); |
| 197 break; |
| 198 case LDBL: |
| 199 arg->f = va_arg(*ap, long double); |
| 200 } |
148 } | 201 } |
149 | 202 |
150 static void out(FILE *f, const wchar_t *s, size_t l) | 203 static void out(FILE* f, const wchar_t* s, size_t l) { |
151 { | 204 while (l-- && !(f->flags & F_ERR)) |
152 » while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f); | 205 fputwc(*s++, f); |
153 } | 206 } |
154 | 207 |
155 static int getint(wchar_t **s) { | 208 static int getint(wchar_t** s) { |
156 » int i; | 209 int i; |
157 » for (i=0; iswdigit(**s); (*s)++) | 210 for (i = 0; iswdigit(**s); (*s)++) |
158 » » i = 10*i + (**s-'0'); | 211 i = 10 * i + (**s - '0'); |
159 » return i; | 212 return i; |
160 } | 213 } |
161 | 214 |
162 static const char sizeprefix['y'-'a'] = { | 215 static const char sizeprefix['y' - 'a'] = |
163 ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L', | 216 {['a' - 'a'] = 'L', ['e' - 'a'] = 'L', ['f' - 'a'] = 'L', ['g' - 'a'] = 'L', |
164 ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j', | 217 ['d' - 'a'] = 'j', ['i' - 'a'] = 'j', ['o' - 'a'] = 'j', ['u' - 'a'] = 'j', |
165 ['p'-'a']='j' | 218 ['x' - 'a'] = 'j', ['p' - 'a'] = 'j'}; |
166 }; | 219 |
167 | 220 static int wprintf_core(FILE* f, |
168 static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
arg, int *nl_type) | 221 const wchar_t* fmt, |
169 { | 222 va_list* ap, |
170 » wchar_t *a, *z, *s=(wchar_t *)fmt; | 223 union arg* nl_arg, |
171 » unsigned l10n=0, litpct, fl; | 224 int* nl_type) { |
172 » int w, p; | 225 wchar_t *a, *z, *s = (wchar_t *)fmt; |
173 » union arg arg; | 226 unsigned l10n = 0, litpct, fl; |
174 » int argpos; | 227 int w, p; |
175 » unsigned st, ps; | 228 union arg arg; |
176 » int cnt=0, l=0; | 229 int argpos; |
177 » int i; | 230 unsigned st, ps; |
178 » int t; | 231 int cnt = 0, l = 0; |
179 » char *bs; | 232 int i; |
180 » char charfmt[16]; | 233 int t; |
181 » wchar_t wc; | 234 char* bs; |
182 | 235 char charfmt[16]; |
183 » for (;;) { | 236 wchar_t wc; |
184 » » /* Update output count, end loop when fmt is exhausted */ | 237 |
185 » » if (cnt >= 0) { | 238 for (;;) { |
186 » » » if (l > INT_MAX - cnt) { | 239 /* Update output count, end loop when fmt is exhausted */ |
187 » » » » if (!ferror(f)) errno = EOVERFLOW; | 240 if (cnt >= 0) { |
188 » » » » cnt = -1; | 241 if (l > INT_MAX - cnt) { |
189 » » » } else cnt += l; | 242 if (!ferror(f)) |
190 » » } | 243 errno = EOVERFLOW; |
191 » » if (!*s) break; | 244 cnt = -1; |
192 | 245 } else |
193 » » /* Handle literal text and %% format specifiers */ | 246 cnt += l; |
194 » » for (a=s; *s && *s!='%'; s++); | 247 } |
195 » » litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */ | 248 if (!*s) |
196 » » z = s+litpct; | 249 break; |
197 » » s += 2*litpct; | 250 |
198 » » l = z-a; | 251 /* Handle literal text and %% format specifiers */ |
199 » » if (f) out(f, a, l); | 252 for (a = s; *s && *s != '%'; s++) |
200 » » if (l) continue; | 253 ; |
201 | 254 litpct = wcsspn(s, L"%") / 2; /* Optimize %%%% runs */ |
202 » » if (iswdigit(s[1]) && s[2]=='$') { | 255 z = s + litpct; |
203 » » » l10n=1; | 256 s += 2 * litpct; |
204 » » » argpos = s[1]-'0'; | 257 l = z - a; |
205 » » » s+=3; | 258 if (f) |
206 » » } else { | 259 out(f, a, l); |
207 » » » argpos = -1; | 260 if (l) |
208 » » » s++; | 261 continue; |
209 » » } | 262 |
210 | 263 if (iswdigit(s[1]) && s[2] == '$') { |
211 » » /* Read modifier flags */ | 264 l10n = 1; |
212 » » for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<(*s-' '))); s++
) | 265 argpos = s[1] - '0'; |
213 » » » fl |= 1U<<(*s-' '); | 266 s += 3; |
214 | 267 } else { |
215 » » /* Read field width */ | 268 argpos = -1; |
216 » » if (*s=='*') { | 269 s++; |
217 » » » if (iswdigit(s[1]) && s[2]=='$') { | 270 } |
218 » » » » l10n=1; | 271 |
219 » » » » nl_type[s[1]-'0'] = INT; | 272 /* Read modifier flags */ |
220 » » » » w = nl_arg[s[1]-'0'].i; | 273 for (fl = 0; (unsigned)*s - ' ' < 32 && (FLAGMASK & (1U << (*s - ' '))); |
221 » » » » s+=3; | 274 s++) |
222 » » » } else if (!l10n) { | 275 fl |= 1U << (*s - ' '); |
223 » » » » w = f ? va_arg(*ap, int) : 0; | 276 |
224 » » » » s++; | 277 /* Read field width */ |
225 » » » } else return -1; | 278 if (*s == '*') { |
226 » » » if (w<0) fl|=LEFT_ADJ, w=-w; | 279 if (iswdigit(s[1]) && s[2] == '$') { |
227 » » } else if ((w=getint(&s))<0) return -1; | 280 l10n = 1; |
228 | 281 nl_type[s[1] - '0'] = INT; |
229 » » /* Read precision */ | 282 w = nl_arg[s[1] - '0'].i; |
230 » » if (*s=='.' && s[1]=='*') { | 283 s += 3; |
231 » » » if (isdigit(s[2]) && s[3]=='$') { | 284 } else if (!l10n) { |
232 » » » » nl_type[s[2]-'0'] = INT; | 285 w = f ? va_arg(*ap, int) : 0; |
233 » » » » p = nl_arg[s[2]-'0'].i; | 286 s++; |
234 » » » » s+=4; | 287 } else |
235 » » » } else if (!l10n) { | 288 return -1; |
236 » » » » p = f ? va_arg(*ap, int) : 0; | 289 if (w < 0) |
237 » » » » s+=2; | 290 fl |= LEFT_ADJ, w = -w; |
238 » » » } else return -1; | 291 } else if ((w = getint(&s)) < 0) |
239 » » } else if (*s=='.') { | 292 return -1; |
240 » » » s++; | 293 |
241 » » » p = getint(&s); | 294 /* Read precision */ |
242 » » } else p = -1; | 295 if (*s == '.' && s[1] == '*') { |
243 | 296 if (isdigit(s[2]) && s[3] == '$') { |
244 » » /* Format specifier state machine */ | 297 nl_type[s[2] - '0'] = INT; |
245 » » st=0; | 298 p = nl_arg[s[2] - '0'].i; |
246 » » do { | 299 s += 4; |
247 » » » if (OOB(*s)) return -1; | 300 } else if (!l10n) { |
248 » » » ps=st; | 301 p = f ? va_arg(*ap, int) : 0; |
249 » » » st=states[st]S(*s++); | 302 s += 2; |
250 » » } while (st-1<STOP); | 303 } else |
251 » » if (!st) return -1; | 304 return -1; |
252 | 305 } else if (*s == '.') { |
253 » » /* Check validity of argument type (nl/normal) */ | 306 s++; |
254 » » if (st==NOARG) { | 307 p = getint(&s); |
255 » » » if (argpos>=0) return -1; | 308 } else |
256 » » } else { | 309 p = -1; |
257 » » » if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; | 310 |
258 » » » else if (f) pop_arg(&arg, st, ap); | 311 /* Format specifier state machine */ |
259 » » » else return 0; | 312 st = 0; |
260 » » } | 313 do { |
261 | 314 if (OOB(*s)) |
262 » » if (!f) continue; | 315 return -1; |
263 » » t = s[-1]; | 316 ps = st; |
264 » » if (ps && (t&15)==3) t&=~32; | 317 st = states[st] S(*s++); |
265 | 318 } while (st - 1 < STOP); |
266 » » switch (t) { | 319 if (!st) |
267 » » case 'n': | 320 return -1; |
268 » » » switch(ps) { | 321 |
269 » » » case BARE: *(int *)arg.p = cnt; break; | 322 /* Check validity of argument type (nl/normal) */ |
270 » » » case LPRE: *(long *)arg.p = cnt; break; | 323 if (st == NOARG) { |
271 » » » case LLPRE: *(long long *)arg.p = cnt; break; | 324 if (argpos >= 0) |
272 » » » case HPRE: *(unsigned short *)arg.p = cnt; break; | 325 return -1; |
273 » » » case HHPRE: *(unsigned char *)arg.p = cnt; break; | 326 } else { |
274 » » » case ZTPRE: *(size_t *)arg.p = cnt; break; | 327 if (argpos >= 0) |
275 » » » case JPRE: *(uintmax_t *)arg.p = cnt; break; | 328 nl_type[argpos] = st, arg = nl_arg[argpos]; |
276 » » » } | 329 else if (f) |
277 » » » continue; | 330 pop_arg(&arg, st, ap); |
278 » » case 'c': | 331 else |
279 » » » fputwc(btowc(arg.i), f); | 332 return 0; |
280 » » » l = 1; | 333 } |
281 » » » continue; | 334 |
282 » » case 'C': | 335 if (!f) |
283 » » » fputwc(arg.i, f); | 336 continue; |
284 » » » l = 1; | 337 t = s[-1]; |
285 » » » continue; | 338 if (ps && (t & 15) == 3) |
286 » » case 'S': | 339 t &= ~32; |
287 » » » a = arg.p; | 340 |
288 » » » z = wmemchr(a, 0, p); | 341 switch (t) { |
289 » » » if (z) p=z-a; | 342 case 'n': |
290 » » » if (w<p) w=p; | 343 switch (ps) { |
291 » » » if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); | 344 case BARE: |
292 » » » out(f, a, p); | 345 *(int*)arg.p = cnt; |
293 » » » if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); | 346 break; |
294 » » » l=w; | 347 case LPRE: |
295 » » » continue; | 348 *(long*)arg.p = cnt; |
296 » » case 'm': | 349 break; |
297 » » » arg.p = strerror(errno); | 350 case LLPRE: |
298 » » case 's': | 351 *(long long*)arg.p = cnt; |
299 » » » if (!arg.p) arg.p = "(null)"; | 352 break; |
300 » » » bs = arg.p; | 353 case HPRE: |
301 » » » if (p<0) p = INT_MAX; | 354 *(unsigned short*)arg.p = cnt; |
302 » » » for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs
+=i, l++); | 355 break; |
303 » » » if (i<0) return -1; | 356 case HHPRE: |
304 » » » p=l; | 357 *(unsigned char*)arg.p = cnt; |
305 » » » if (w<p) w=p; | 358 break; |
306 » » » if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); | 359 case ZTPRE: |
307 » » » bs = arg.p; | 360 *(size_t*)arg.p = cnt; |
308 » » » while (l--) { | 361 break; |
309 » » » » i=mbtowc(&wc, bs, MB_LEN_MAX); | 362 case JPRE: |
310 » » » » bs+=i; | 363 *(uintmax_t*)arg.p = cnt; |
311 » » » » fputwc(wc, f); | 364 break; |
312 » » » } | 365 } |
313 » » » if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); | 366 continue; |
314 » » » l=w; | 367 case 'c': |
315 » » » continue; | 368 fputwc(btowc(arg.i), f); |
316 » » } | 369 l = 1; |
317 | 370 continue; |
318 » » snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c", | 371 case 'C': |
319 » » » (fl & ALT_FORM) ? "#" : "", | 372 fputwc(arg.i, f); |
320 » » » (fl & MARK_POS) ? "+" : "", | 373 l = 1; |
321 » » » (fl & LEFT_ADJ) ? "-" : "", | 374 continue; |
322 » » » (fl & PAD_POS) ? " " : "", | 375 case 'S': |
323 » » » (fl & ZERO_PAD) ? "0" : "", | 376 a = arg.p; |
324 » » » sizeprefix[(t|32)-'a'], t); | 377 z = wmemchr(a, 0, p); |
325 | 378 if (z) |
326 » » switch (t|32) { | 379 p = z - a; |
327 » » case 'a': case 'e': case 'f': case 'g': | 380 if (w < p) |
328 » » » l = fprintf(f, charfmt, w, p, arg.f); | 381 w = p; |
329 » » » break; | 382 if (!(fl & LEFT_ADJ)) |
330 » » case 'd': case 'i': case 'o': case 'u': case 'x': case 'p': | 383 fprintf(f, "%.*s", w - p, ""); |
331 » » » l = fprintf(f, charfmt, w, p, arg.i); | 384 out(f, a, p); |
332 » » » break; | 385 if ((fl & LEFT_ADJ)) |
333 » » } | 386 fprintf(f, "%.*s", w - p, ""); |
334 » } | 387 l = w; |
335 | 388 continue; |
336 » if (f) return cnt; | 389 case 'm': |
337 » if (!l10n) return 0; | 390 arg.p = strerror(errno); |
338 | 391 case 's': |
339 » for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) | 392 if (!arg.p) |
340 » » pop_arg(nl_arg+i, nl_type[i], ap); | 393 arg.p = "(null)"; |
341 » for (; i<=NL_ARGMAX && !nl_type[i]; i++); | 394 bs = arg.p; |
342 » if (i<=NL_ARGMAX) return -1; | 395 if (p < 0) |
343 » return 1; | 396 p = INT_MAX; |
| 397 for (i = l = 0; l < p && (i = mbtowc(&wc, bs, MB_LEN_MAX)) > 0; |
| 398 bs += i, l++) |
| 399 ; |
| 400 if (i < 0) |
| 401 return -1; |
| 402 p = l; |
| 403 if (w < p) |
| 404 w = p; |
| 405 if (!(fl & LEFT_ADJ)) |
| 406 fprintf(f, "%.*s", w - p, ""); |
| 407 bs = arg.p; |
| 408 while (l--) { |
| 409 i = mbtowc(&wc, bs, MB_LEN_MAX); |
| 410 bs += i; |
| 411 fputwc(wc, f); |
| 412 } |
| 413 if ((fl & LEFT_ADJ)) |
| 414 fprintf(f, "%.*s", w - p, ""); |
| 415 l = w; |
| 416 continue; |
| 417 } |
| 418 |
| 419 snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c", |
| 420 (fl & ALT_FORM) ? "#" : "", (fl & MARK_POS) ? "+" : "", |
| 421 (fl & LEFT_ADJ) ? "-" : "", (fl & PAD_POS) ? " " : "", |
| 422 (fl & ZERO_PAD) ? "0" : "", sizeprefix[(t | 32) - 'a'], t); |
| 423 |
| 424 switch (t | 32) { |
| 425 case 'a': |
| 426 case 'e': |
| 427 case 'f': |
| 428 case 'g': |
| 429 l = fprintf(f, charfmt, w, p, arg.f); |
| 430 break; |
| 431 case 'd': |
| 432 case 'i': |
| 433 case 'o': |
| 434 case 'u': |
| 435 case 'x': |
| 436 case 'p': |
| 437 l = fprintf(f, charfmt, w, p, arg.i); |
| 438 break; |
| 439 } |
| 440 } |
| 441 |
| 442 if (f) |
| 443 return cnt; |
| 444 if (!l10n) |
| 445 return 0; |
| 446 |
| 447 for (i = 1; i <= NL_ARGMAX && nl_type[i]; i++) |
| 448 pop_arg(nl_arg + i, nl_type[i], ap); |
| 449 for (; i <= NL_ARGMAX && !nl_type[i]; i++) |
| 450 ; |
| 451 if (i <= NL_ARGMAX) |
| 452 return -1; |
| 453 return 1; |
344 } | 454 } |
345 | 455 |
346 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap) | 456 int vfwprintf(FILE* restrict f, const wchar_t* restrict fmt, va_list ap) { |
347 { | 457 va_list ap2; |
348 » va_list ap2; | 458 int nl_type[NL_ARGMAX] = {0}; |
349 » int nl_type[NL_ARGMAX] = {0}; | 459 union arg nl_arg[NL_ARGMAX]; |
350 » union arg nl_arg[NL_ARGMAX]; | 460 int olderr; |
351 » int olderr; | 461 int ret; |
352 » int ret; | 462 |
353 | 463 /* the copy allows passing va_list* even if va_list is an array */ |
354 » /* the copy allows passing va_list* even if va_list is an array */ | 464 va_copy(ap2, ap); |
355 » va_copy(ap2, ap); | 465 if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { |
356 » if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { | 466 va_end(ap2); |
357 » » va_end(ap2); | 467 return -1; |
358 » » return -1; | 468 } |
359 » } | 469 |
360 | 470 FLOCK(f); |
361 » FLOCK(f); | 471 fwide(f, 1); |
362 » fwide(f, 1); | 472 olderr = f->flags & F_ERR; |
363 » olderr = f->flags & F_ERR; | 473 f->flags &= ~F_ERR; |
364 » f->flags &= ~F_ERR; | 474 ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); |
365 » ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); | 475 if (f->flags & F_ERR) |
366 » if (f->flags & F_ERR) ret = -1; | 476 ret = -1; |
367 » f->flags |= olderr; | 477 f->flags |= olderr; |
368 » FUNLOCK(f); | 478 FUNLOCK(f); |
369 » va_end(ap2); | 479 va_end(ap2); |
370 » return ret; | 480 return ret; |
371 } | 481 } |
OLD | NEW |