| 150 | }; |
| 151 | |
| 152 | static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type) |
| 153 | { |
| 154 | wchar_t *a, *z, *s=(wchar_t *)fmt; |
| 155 | unsigned l10n=0, fl; |
| 156 | int w, p, xp; |
| 157 | union arg arg; |
| 158 | int argpos; |
| 159 | unsigned st, ps; |
| 160 | int cnt=0, l=0; |
| 161 | int i; |
| 162 | int t; |
| 163 | char *bs; |
| 164 | char charfmt[16]; |
| 165 | wchar_t wc; |
| 166 | |
| 167 | for (;;) { |
| 168 | /* This error is only specified for snprintf, but since it's |
| 169 | * unspecified for other forms, do the same. Stop immediately |
| 170 | * on overflow; otherwise %n could produce wrong results. */ |
| 171 | if (l > INT_MAX - cnt) goto overflow; |
| 172 | |
| 173 | /* Update output count, end loop when fmt is exhausted */ |
| 174 | cnt += l; |
| 175 | if (!*s) break; |
| 176 | |
| 177 | /* Handle literal text and %% format specifiers */ |
| 178 | for (a=s; *s && *s!='%'; s++); |
| 179 | for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2); |
| 180 | if (z-a > INT_MAX-cnt) goto overflow; |
| 181 | l = z-a; |
| 182 | if (f) out(f, a, l); |
| 183 | if (l) continue; |
| 184 | |
| 185 | if (iswdigit(s[1]) && s[2]=='$') { |
| 186 | l10n=1; |
| 187 | argpos = s[1]-'0'; |
| 188 | s+=3; |
| 189 | } else { |
| 190 | argpos = -1; |
| 191 | s++; |
| 192 | } |
| 193 | |
| 194 | /* Read modifier flags */ |
| 195 | for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++) |
| 196 | fl |= 1U<<*s-' '; |
| 197 | |
| 198 | /* Read field width */ |
| 199 | if (*s=='*') { |
| 200 | if (iswdigit(s[1]) && s[2]=='$') { |
| 201 | l10n=1; |
| 202 | nl_type[s[1]-'0'] = INT; |
| 203 | w = nl_arg[s[1]-'0'].i; |
| 204 | s+=3; |
| 205 | } else if (!l10n) { |
| 206 | w = f ? va_arg(*ap, int) : 0; |
| 207 | s++; |
| 208 | } else goto inval; |
| 209 | if (w<0) fl|=LEFT_ADJ, w=-w; |
no test coverage detected