blob: a05fffe00695c9e21afff1345575c79984c51b62 [file] [log] [blame]
Elliott Hughesf1ada792014-05-02 17:56:56 -07001/* $OpenBSD: vfwscanf.c,v 1.4 2014/03/19 05:17:01 guenther Exp $ */
Elliott Hughes01ae00f2014-04-29 16:28:56 -07002/*-
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
Elliott Hughes01ae00f2014-04-29 16:28:56 -070034#include <inttypes.h>
35#include <limits.h>
36#include <locale.h>
37#include <stdarg.h>
38#include <stddef.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <wctype.h>
43#include "local.h"
44
Elliott Hughes01ae00f2014-04-29 16:28:56 -070045#include "floatio.h"
Elliott Hughes01ae00f2014-04-29 16:28:56 -070046
47#define BUF 513 /* Maximum length of numeric string. */
48
49/*
50 * Flags used during conversion.
51 */
52#define LONG 0x00001 /* l: long or double */
53#define LONGDBL 0x00002 /* L: long double */
54#define SHORT 0x00004 /* h: short */
55#define SHORTSHORT 0x00008 /* hh: 8 bit integer */
56#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
57#define POINTER 0x00020 /* p: void * (as hex) */
58#define SIZEINT 0x00040 /* z: (signed) size_t */
59#define MAXINT 0x00080 /* j: intmax_t */
60#define PTRINT 0x00100 /* t: ptrdiff_t */
61#define NOSKIP 0x00200 /* [ or c: do not skip blanks */
62#define SUPPRESS 0x00400 /* *: suppress assignment */
63#define UNSIGNED 0x00800 /* %[oupxX] conversions */
64
65/*
66 * The following are used in numeric conversions only:
67 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
68 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
69 */
70#define SIGNOK 0x01000 /* +/- is (still) legal */
71#define HAVESIGN 0x02000 /* sign detected */
72#define NDIGITS 0x04000 /* no digits detected */
73
74#define DPTOK 0x08000 /* (float) decimal point is still legal */
75#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
76
77#define PFXOK 0x08000 /* 0x prefix is (still) legal */
78#define NZDIGITS 0x10000 /* no zero digits detected */
79
80/*
81 * Conversion types.
82 */
83#define CT_CHAR 0 /* %c conversion */
84#define CT_CCL 1 /* %[...] conversion */
85#define CT_STRING 2 /* %s conversion */
86#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
87#define CT_FLOAT 4 /* floating, i.e., strtod */
88
89#define u_char unsigned char
90#define u_long unsigned long
91
92#define INCCL(_c) \
93 (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
94 (wmemchr(ccls, (_c), ccle - ccls) != NULL))
95
Elliott Hughes7f0849f2016-08-26 16:17:17 -070096#pragma GCC diagnostic push
97#pragma GCC diagnostic ignored "-Wframe-larger-than="
98
Elliott Hughes01ae00f2014-04-29 16:28:56 -070099/*
100 * vfwscanf
101 */
102int
103__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap)
104{
105 wint_t c; /* character from format, or conversion */
106 size_t width; /* field width, or 0 */
107 wchar_t *p; /* points into all kinds of strings */
108 int n; /* handy integer */
109 int flags; /* flags as defined above */
110 wchar_t *p0; /* saves original value of p when necessary */
111 int nassigned; /* number of fields assigned */
112 int nconversions; /* number of conversions */
113 int nread; /* number of characters consumed from fp */
114 int base; /* base argument to strtoimax/strtouimax */
115 wchar_t buf[BUF]; /* buffer for numeric conversions */
116 const wchar_t *ccls; /* character class start */
117 const wchar_t *ccle; /* character class end */
118 int cclcompl; /* ccl is complemented? */
119 wint_t wi; /* handy wint_t */
120 char *mbp; /* multibyte string pointer for %c %s %[ */
121 size_t nconv; /* number of bytes in mb. conversion */
122 char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
123 mbstate_t mbs;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700124
125 /* `basefix' is used to avoid `if' tests in the integer scanner */
126 static short basefix[17] =
127 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
128
129 _SET_ORIENTATION(fp, 1);
130
131 nassigned = 0;
132 nconversions = 0;
133 nread = 0;
134 base = 0; /* XXX just to keep gcc happy */
135 ccls = ccle = NULL;
136 for (;;) {
137 c = *fmt++;
138 if (c == 0) {
139 return (nassigned);
140 }
141 if (iswspace(c)) {
142 while ((c = __fgetwc_unlock(fp)) != WEOF &&
143 iswspace(c))
144 ;
145 if (c != WEOF)
146 __ungetwc(c, fp);
147 continue;
148 }
149 if (c != '%')
150 goto literal;
151 width = 0;
152 flags = 0;
153 /*
154 * switch on the format. continue if done;
155 * break once format type is derived.
156 */
157again: c = *fmt++;
158 switch (c) {
159 case '%':
160literal:
161 if ((wi = __fgetwc_unlock(fp)) == WEOF)
162 goto input_failure;
163 if (wi != c) {
164 __ungetwc(wi, fp);
165 goto input_failure;
166 }
167 nread++;
168 continue;
169
170 case '*':
171 flags |= SUPPRESS;
172 goto again;
173 case 'j':
174 flags |= MAXINT;
175 goto again;
176 case 'L':
177 flags |= LONGDBL;
178 goto again;
179 case 'h':
180 if (*fmt == 'h') {
181 fmt++;
182 flags |= SHORTSHORT;
183 } else {
184 flags |= SHORT;
185 }
186 goto again;
187 case 'l':
188 if (*fmt == 'l') {
189 fmt++;
190 flags |= LLONG;
191 } else {
192 flags |= LONG;
193 }
194 goto again;
195 case 'q':
196 flags |= LLONG; /* deprecated */
197 goto again;
198 case 't':
199 flags |= PTRINT;
200 goto again;
201 case 'z':
202 flags |= SIZEINT;
203 goto again;
204
205 case '0': case '1': case '2': case '3': case '4':
206 case '5': case '6': case '7': case '8': case '9':
207 width = width * 10 + c - '0';
208 goto again;
209
210 /*
211 * Conversions.
212 * Those marked `compat' are for 4.[123]BSD compatibility.
213 *
214 * (According to ANSI, E and X formats are supposed
215 * to the same as e and x. Sorry about that.)
216 */
217 case 'D': /* compat */
218 flags |= LONG;
219 /* FALLTHROUGH */
220 case 'd':
221 c = CT_INT;
222 base = 10;
223 break;
224
225 case 'i':
226 c = CT_INT;
227 base = 0;
228 break;
229
230 case 'O': /* compat */
231 flags |= LONG;
232 /* FALLTHROUGH */
233 case 'o':
234 c = CT_INT;
235 flags |= UNSIGNED;
236 base = 8;
237 break;
238
239 case 'u':
240 c = CT_INT;
241 flags |= UNSIGNED;
242 base = 10;
243 break;
244
245 case 'X':
246 case 'x':
247 flags |= PFXOK; /* enable 0x prefixing */
248 c = CT_INT;
249 flags |= UNSIGNED;
250 base = 16;
251 break;
252
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700253 case 'e': case 'E':
254 case 'f': case 'F':
255 case 'g': case 'G':
256 case 'a': case 'A':
257 c = CT_FLOAT;
258 break;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700259
260 case 's':
261 c = CT_STRING;
262 break;
263
264 case '[':
265 ccls = fmt;
266 if (*fmt == '^') {
267 cclcompl = 1;
268 fmt++;
269 } else
270 cclcompl = 0;
271 if (*fmt == ']')
272 fmt++;
273 while (*fmt != '\0' && *fmt != ']')
274 fmt++;
275 ccle = fmt;
276 fmt++;
277 flags |= NOSKIP;
278 c = CT_CCL;
279 break;
280
281 case 'c':
282 flags |= NOSKIP;
283 c = CT_CHAR;
284 break;
285
286 case 'p': /* pointer format is like hex */
287 flags |= POINTER | PFXOK;
288 c = CT_INT;
289 flags |= UNSIGNED;
290 base = 16;
291 break;
292
293 case 'n':
294 nconversions++;
295 if (flags & SUPPRESS)
296 continue;
297 if (flags & SHORTSHORT)
Elliott Hughesf1ada792014-05-02 17:56:56 -0700298 *va_arg(ap, signed char *) = nread;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700299 else if (flags & SHORT)
300 *va_arg(ap, short *) = nread;
301 else if (flags & LONG)
302 *va_arg(ap, long *) = nread;
303 else if (flags & SIZEINT)
304 *va_arg(ap, ssize_t *) = nread;
305 else if (flags & PTRINT)
306 *va_arg(ap, ptrdiff_t *) = nread;
307 else if (flags & LLONG)
308 *va_arg(ap, long long *) = nread;
309 else if (flags & MAXINT)
310 *va_arg(ap, intmax_t *) = nread;
311 else
312 *va_arg(ap, int *) = nread;
313 continue;
314
315 /*
316 * Disgusting backwards compatibility hacks. XXX
317 */
318 case '\0': /* compat */
319 return (EOF);
320
321 default: /* compat */
Elliott Hughesf1ada792014-05-02 17:56:56 -0700322 if (iswupper(c))
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700323 flags |= LONG;
324 c = CT_INT;
325 base = 10;
326 break;
327 }
328
329 /*
330 * Consume leading white space, except for formats
331 * that suppress this.
332 */
333 if ((flags & NOSKIP) == 0) {
334 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
335 iswspace(wi))
336 nread++;
337 if (wi == WEOF)
338 goto input_failure;
339 __ungetwc(wi, fp);
340 }
341
342 /*
343 * Do the conversion.
344 */
345 switch (c) {
346
347 case CT_CHAR:
348 /* scan arbitrary characters (sets NOSKIP) */
349 if (width == 0)
350 width = 1;
351 if (flags & LONG) {
352 if (!(flags & SUPPRESS))
353 p = va_arg(ap, wchar_t *);
354 n = 0;
355 while (width-- != 0 &&
356 (wi = __fgetwc_unlock(fp)) != WEOF) {
357 if (!(flags & SUPPRESS))
358 *p++ = (wchar_t)wi;
359 n++;
360 }
361 if (n == 0)
362 goto input_failure;
363 nread += n;
364 if (!(flags & SUPPRESS))
365 nassigned++;
366 } else {
367 if (!(flags & SUPPRESS))
368 mbp = va_arg(ap, char *);
369 n = 0;
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700370 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700371 while (width != 0 &&
372 (wi = __fgetwc_unlock(fp)) != WEOF) {
373 if (width >= MB_CUR_MAX &&
374 !(flags & SUPPRESS)) {
375 nconv = wcrtomb(mbp, wi, &mbs);
376 if (nconv == (size_t)-1)
377 goto input_failure;
378 } else {
379 nconv = wcrtomb(mbbuf, wi,
380 &mbs);
381 if (nconv == (size_t)-1)
382 goto input_failure;
383 if (nconv > width) {
384 __ungetwc(wi, fp);
385 break;
386 }
387 if (!(flags & SUPPRESS))
388 memcpy(mbp, mbbuf,
389 nconv);
390 }
391 if (!(flags & SUPPRESS))
392 mbp += nconv;
393 width -= nconv;
394 n++;
395 }
396 if (n == 0)
397 goto input_failure;
398 nread += n;
399 if (!(flags & SUPPRESS))
400 nassigned++;
401 }
402 nconversions++;
403 break;
404
405 case CT_CCL:
406 /* scan a (nonempty) character class (sets NOSKIP) */
407 if (width == 0)
408 width = (size_t)~0; /* `infinity' */
409 /* take only those things in the class */
410 if ((flags & SUPPRESS) && (flags & LONG)) {
411 n = 0;
412 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
413 width-- != 0 && INCCL(wi))
414 n++;
415 if (wi != WEOF)
416 __ungetwc(wi, fp);
417 if (n == 0)
418 goto match_failure;
419 } else if (flags & LONG) {
420 p0 = p = va_arg(ap, wchar_t *);
421 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
422 width-- != 0 && INCCL(wi))
423 *p++ = (wchar_t)wi;
424 if (wi != WEOF)
425 __ungetwc(wi, fp);
426 n = p - p0;
427 if (n == 0)
428 goto match_failure;
429 *p = 0;
430 nassigned++;
431 } else {
432 if (!(flags & SUPPRESS))
433 mbp = va_arg(ap, char *);
434 n = 0;
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700435 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700436 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
437 width != 0 && INCCL(wi)) {
438 if (width >= MB_CUR_MAX &&
439 !(flags & SUPPRESS)) {
440 nconv = wcrtomb(mbp, wi, &mbs);
441 if (nconv == (size_t)-1)
442 goto input_failure;
443 } else {
444 nconv = wcrtomb(mbbuf, wi,
445 &mbs);
446 if (nconv == (size_t)-1)
447 goto input_failure;
448 if (nconv > width)
449 break;
450 if (!(flags & SUPPRESS))
451 memcpy(mbp, mbbuf,
452 nconv);
453 }
454 if (!(flags & SUPPRESS))
455 mbp += nconv;
456 width -= nconv;
457 n++;
458 }
459 if (wi != WEOF)
460 __ungetwc(wi, fp);
461 if (!(flags & SUPPRESS)) {
462 *mbp = 0;
463 nassigned++;
464 }
465 }
466 nread += n;
467 nconversions++;
468 break;
469
470 case CT_STRING:
471 /* like CCL, but zero-length string OK, & no NOSKIP */
472 if (width == 0)
473 width = (size_t)~0;
474 if ((flags & SUPPRESS) && (flags & LONG)) {
475 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
476 width-- != 0 &&
477 !iswspace(wi))
478 nread++;
479 if (wi != WEOF)
480 __ungetwc(wi, fp);
481 } else if (flags & LONG) {
482 p0 = p = va_arg(ap, wchar_t *);
483 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
484 width-- != 0 &&
485 !iswspace(wi)) {
486 *p++ = (wchar_t)wi;
487 nread++;
488 }
489 if (wi != WEOF)
490 __ungetwc(wi, fp);
491 *p = 0;
492 nassigned++;
493 } else {
494 if (!(flags & SUPPRESS))
495 mbp = va_arg(ap, char *);
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700496 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700497 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
498 width != 0 &&
499 !iswspace(wi)) {
500 if (width >= MB_CUR_MAX &&
501 !(flags & SUPPRESS)) {
502 nconv = wcrtomb(mbp, wi, &mbs);
503 if (nconv == (size_t)-1)
504 goto input_failure;
505 } else {
506 nconv = wcrtomb(mbbuf, wi,
507 &mbs);
508 if (nconv == (size_t)-1)
509 goto input_failure;
510 if (nconv > width)
511 break;
512 if (!(flags & SUPPRESS))
513 memcpy(mbp, mbbuf,
514 nconv);
515 }
516 if (!(flags & SUPPRESS))
517 mbp += nconv;
518 width -= nconv;
519 nread++;
520 }
521 if (wi != WEOF)
522 __ungetwc(wi, fp);
523 if (!(flags & SUPPRESS)) {
524 *mbp = 0;
525 nassigned++;
526 }
527 }
528 nconversions++;
529 continue;
530
531 case CT_INT:
532 /* scan an integer as if by strtoimax/strtoumax */
533 if (width == 0 || width > sizeof(buf) /
534 sizeof(*buf) - 1)
535 width = sizeof(buf) / sizeof(*buf) - 1;
536 flags |= SIGNOK | NDIGITS | NZDIGITS;
537 for (p = buf; width; width--) {
538 c = __fgetwc_unlock(fp);
539 /*
540 * Switch on the character; `goto ok'
541 * if we accept it as a part of number.
542 */
543 switch (c) {
544
545 /*
546 * The digit 0 is always legal, but is
547 * special. For %i conversions, if no
548 * digits (zero or nonzero) have been
549 * scanned (only signs), we will have
550 * base==0. In that case, we should set
551 * it to 8 and enable 0x prefixing.
552 * Also, if we have not scanned zero digits
553 * before this, do not turn off prefixing
554 * (someone else will turn it off if we
555 * have scanned any nonzero digits).
556 */
557 case '0':
558 if (base == 0) {
559 base = 8;
560 flags |= PFXOK;
561 }
562 if (flags & NZDIGITS)
563 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
564 else
565 flags &= ~(SIGNOK|PFXOK|NDIGITS);
566 goto ok;
567
568 /* 1 through 7 always legal */
569 case '1': case '2': case '3':
570 case '4': case '5': case '6': case '7':
571 base = basefix[base];
572 flags &= ~(SIGNOK | PFXOK | NDIGITS);
573 goto ok;
574
575 /* digits 8 and 9 ok iff decimal or hex */
576 case '8': case '9':
577 base = basefix[base];
578 if (base <= 8)
579 break; /* not legal here */
580 flags &= ~(SIGNOK | PFXOK | NDIGITS);
581 goto ok;
582
583 /* letters ok iff hex */
584 case 'A': case 'B': case 'C':
585 case 'D': case 'E': case 'F':
586 case 'a': case 'b': case 'c':
587 case 'd': case 'e': case 'f':
588 /* no need to fix base here */
589 if (base <= 10)
590 break; /* not legal here */
591 flags &= ~(SIGNOK | PFXOK | NDIGITS);
592 goto ok;
593
594 /* sign ok only as first character */
595 case '+': case '-':
596 if (flags & SIGNOK) {
597 flags &= ~SIGNOK;
598 flags |= HAVESIGN;
599 goto ok;
600 }
601 break;
602
603 /*
604 * x ok iff flag still set and 2nd char (or
605 * 3rd char if we have a sign).
606 */
607 case 'x': case 'X':
608 if ((flags & PFXOK) && p ==
609 buf + 1 + !!(flags & HAVESIGN)) {
610 base = 16; /* if %i */
611 flags &= ~PFXOK;
612 goto ok;
613 }
614 break;
615 }
616
617 /*
618 * If we got here, c is not a legal character
619 * for a number. Stop accumulating digits.
620 */
621 if (c != WEOF)
622 __ungetwc(c, fp);
623 break;
624 ok:
625 /*
626 * c is legal: store it and look at the next.
627 */
628 *p++ = (wchar_t)c;
629 }
630 /*
631 * If we had only a sign, it is no good; push
632 * back the sign. If the number ends in `x',
633 * it was [sign] '0' 'x', so push back the x
634 * and treat it as [sign] '0'.
635 */
636 if (flags & NDIGITS) {
637 if (p > buf)
638 __ungetwc(*--p, fp);
639 goto match_failure;
640 }
641 c = p[-1];
642 if (c == 'x' || c == 'X') {
643 --p;
644 __ungetwc(c, fp);
645 }
646 if ((flags & SUPPRESS) == 0) {
647 uintmax_t res;
648
649 *p = '\0';
650 if (flags & UNSIGNED)
651 res = wcstoimax(buf, NULL, base);
652 else
653 res = wcstoumax(buf, NULL, base);
654 if (flags & POINTER)
655 *va_arg(ap, void **) =
656 (void *)(uintptr_t)res;
657 else if (flags & MAXINT)
658 *va_arg(ap, intmax_t *) = res;
659 else if (flags & LLONG)
660 *va_arg(ap, long long *) = res;
661 else if (flags & SIZEINT)
662 *va_arg(ap, ssize_t *) = res;
663 else if (flags & PTRINT)
664 *va_arg(ap, ptrdiff_t *) = res;
665 else if (flags & LONG)
666 *va_arg(ap, long *) = res;
667 else if (flags & SHORT)
668 *va_arg(ap, short *) = res;
669 else if (flags & SHORTSHORT)
Elliott Hughesf1ada792014-05-02 17:56:56 -0700670 *va_arg(ap, signed char *) = res;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700671 else
672 *va_arg(ap, int *) = res;
673 nassigned++;
674 }
675 nread += p - buf;
676 nconversions++;
677 break;
678
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700679 case CT_FLOAT:
680 /* scan a floating point number as if by strtod */
681 if (width == 0 || width > sizeof(buf) /
682 sizeof(*buf) - 1)
683 width = sizeof(buf) / sizeof(*buf) - 1;
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700684 if ((width = wparsefloat(fp, buf, buf + width)) == 0)
685 goto match_failure;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700686 if ((flags & SUPPRESS) == 0) {
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700687 if (flags & LONGDBL) {
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700688 long double res = wcstold(buf, &p);
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700689 *va_arg(ap, long double *) = res;
690 } else if (flags & LONG) {
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700691 double res = wcstod(buf, &p);
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700692 *va_arg(ap, double *) = res;
693 } else {
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700694 float res = wcstof(buf, &p);
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700695 *va_arg(ap, float *) = res;
696 }
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700697 if (p - buf != (ptrdiff_t)width) abort();
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700698 nassigned++;
699 }
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700700 nread += width;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700701 nconversions++;
702 break;
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700703 }
704 }
705input_failure:
706 return (nconversions != 0 ? nassigned : EOF);
707match_failure:
708 return (nassigned);
709}
Elliott Hughes7f0849f2016-08-26 16:17:17 -0700710#pragma GCC diagnostic pop
Elliott Hughes01ae00f2014-04-29 16:28:56 -0700711
712int
713vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap)
714{
715 int r;
716
717 FLOCKFILE(fp);
718 r = __vfwscanf(fp, fmt, ap);
719 FUNLOCKFILE(fp);
720 return (r);
721}