1 /* $OpenBSD: vfwscanf.c,v 1.8 2022/12/27 17:10:06 jmc Exp $ */
2 /*-
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
34 #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
45 #ifdef FLOATING_POINT
46 #include <float.h>
47 #include "floatio.h"
48 #endif
49
50 #define BUF 513 /* Maximum length of numeric string. */
51
52 /*
53 * Flags used during conversion.
54 */
55 #define LONG 0x00001 /* l: long or double */
56 #define LONGDBL 0x00002 /* L: long double */
57 #define SHORT 0x00004 /* h: short */
58 #define SHORTSHORT 0x00008 /* hh: 8 bit integer */
59 #define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
60 #define POINTER 0x00020 /* p: void * (as hex) */
61 #define SIZEINT 0x00040 /* z: (signed) size_t */
62 #define MAXINT 0x00080 /* j: intmax_t */
63 #define PTRINT 0x00100 /* t: ptrdiff_t */
64 #define NOSKIP 0x00200 /* [ or c: do not skip blanks */
65 #define SUPPRESS 0x00400 /* *: suppress assignment */
66 #define UNSIGNED 0x00800 /* %[oupxX] conversions */
67
68 /*
69 * The following are used in numeric conversions only:
70 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
71 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
72 */
73 #define SIGNOK 0x01000 /* +/- is (still) legal */
74 #define HAVESIGN 0x02000 /* sign detected */
75 #define NDIGITS 0x04000 /* no digits detected */
76
77 #define DPTOK 0x08000 /* (float) decimal point is still legal */
78 #define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
79
80 #define PFXOK 0x08000 /* 0x prefix is (still) legal */
81 #define NZDIGITS 0x10000 /* no zero digits detected */
82
83 /*
84 * Conversion types.
85 */
86 #define CT_CHAR 0 /* %c conversion */
87 #define CT_CCL 1 /* %[...] conversion */
88 #define CT_STRING 2 /* %s conversion */
89 #define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
90 #define CT_FLOAT 4 /* floating, i.e., strtod */
91
92 #define u_char unsigned char
93 #define u_long unsigned long
94
95 #define INCCL(_c) \
96 (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
97 (wmemchr(ccls, (_c), ccle - ccls) != NULL))
98
99 /*
100 * vfwscanf
101 */
102 int
__vfwscanf(FILE * __restrict fp,const wchar_t * __restrict fmt,__va_list ap)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;
124 #ifdef FLOATING_POINT
125 wchar_t decimal_point = 0;
126 #endif
127
128 /* `basefix' is used to avoid `if' tests in the integer scanner */
129 static short basefix[17] =
130 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
131
132 _SET_ORIENTATION(fp, 1);
133
134 nassigned = 0;
135 nconversions = 0;
136 nread = 0;
137 base = 0; /* XXX just to keep gcc happy */
138 ccls = ccle = NULL;
139 for (;;) {
140 c = *fmt++;
141 if (c == 0) {
142 return (nassigned);
143 }
144 if (iswspace(c)) {
145 while ((c = __fgetwc_unlock(fp)) != WEOF &&
146 iswspace(c))
147 ;
148 if (c != WEOF)
149 __ungetwc(c, fp);
150 continue;
151 }
152 if (c != '%')
153 goto literal;
154 width = 0;
155 flags = 0;
156 /*
157 * switch on the format. continue if done;
158 * break once format type is derived.
159 */
160 again: c = *fmt++;
161 switch (c) {
162 case '%':
163 literal:
164 if ((wi = __fgetwc_unlock(fp)) == WEOF)
165 goto input_failure;
166 if (wi != c) {
167 __ungetwc(wi, fp);
168 goto match_failure;
169 }
170 nread++;
171 continue;
172
173 case '*':
174 flags |= SUPPRESS;
175 goto again;
176 case 'j':
177 flags |= MAXINT;
178 goto again;
179 case 'L':
180 flags |= LONGDBL;
181 goto again;
182 case 'h':
183 if (*fmt == 'h') {
184 fmt++;
185 flags |= SHORTSHORT;
186 } else {
187 flags |= SHORT;
188 }
189 goto again;
190 case 'l':
191 if (*fmt == 'l') {
192 fmt++;
193 flags |= LLONG;
194 } else {
195 flags |= LONG;
196 }
197 goto again;
198 case 'q':
199 flags |= LLONG; /* deprecated */
200 goto again;
201 case 't':
202 flags |= PTRINT;
203 goto again;
204 case 'z':
205 flags |= SIZEINT;
206 goto again;
207
208 case '0': case '1': case '2': case '3': case '4':
209 case '5': case '6': case '7': case '8': case '9':
210 width = width * 10 + c - '0';
211 goto again;
212
213 /*
214 * Conversions.
215 * Those marked `compat' are for 4.[123]BSD compatibility.
216 *
217 * (According to ANSI, E and X formats are supposed
218 * to the same as e and x. Sorry about that.)
219 */
220 case 'D': /* compat */
221 flags |= LONG;
222 /* FALLTHROUGH */
223 case 'd':
224 c = CT_INT;
225 base = 10;
226 break;
227
228 case 'i':
229 c = CT_INT;
230 base = 0;
231 break;
232
233 case 'O': /* compat */
234 flags |= LONG;
235 /* FALLTHROUGH */
236 case 'o':
237 c = CT_INT;
238 flags |= UNSIGNED;
239 base = 8;
240 break;
241
242 case 'u':
243 c = CT_INT;
244 flags |= UNSIGNED;
245 base = 10;
246 break;
247
248 case 'X':
249 case 'x':
250 flags |= PFXOK; /* enable 0x prefixing */
251 c = CT_INT;
252 flags |= UNSIGNED;
253 base = 16;
254 break;
255
256 #ifdef FLOATING_POINT
257 case 'e': case 'E':
258 case 'f': case 'F':
259 case 'g': case 'G':
260 case 'a': case 'A':
261 c = CT_FLOAT;
262 break;
263 #endif
264
265 case 's':
266 c = CT_STRING;
267 break;
268
269 case '[':
270 ccls = fmt;
271 if (*fmt == '^') {
272 cclcompl = 1;
273 fmt++;
274 } else
275 cclcompl = 0;
276 if (*fmt == ']')
277 fmt++;
278 while (*fmt != '\0' && *fmt != ']')
279 fmt++;
280 ccle = fmt;
281 fmt++;
282 flags |= NOSKIP;
283 c = CT_CCL;
284 break;
285
286 case 'c':
287 flags |= NOSKIP;
288 c = CT_CHAR;
289 break;
290
291 case 'p': /* pointer format is like hex */
292 flags |= POINTER | PFXOK;
293 c = CT_INT;
294 flags |= UNSIGNED;
295 base = 16;
296 break;
297
298 case 'n':
299 nconversions++;
300 if (flags & SUPPRESS)
301 continue;
302 if (flags & SHORTSHORT)
303 *va_arg(ap, signed char *) = nread;
304 else if (flags & SHORT)
305 *va_arg(ap, short *) = nread;
306 else if (flags & LONG)
307 *va_arg(ap, long *) = nread;
308 else if (flags & SIZEINT)
309 *va_arg(ap, ssize_t *) = nread;
310 else if (flags & PTRINT)
311 *va_arg(ap, ptrdiff_t *) = nread;
312 else if (flags & LLONG)
313 *va_arg(ap, long long *) = nread;
314 else if (flags & MAXINT)
315 *va_arg(ap, intmax_t *) = nread;
316 else
317 *va_arg(ap, int *) = nread;
318 continue;
319
320 /*
321 * Disgusting backwards compatibility hacks. XXX
322 */
323 case '\0': /* compat */
324 return (EOF);
325
326 default: /* compat */
327 if (iswupper(c))
328 flags |= LONG;
329 c = CT_INT;
330 base = 10;
331 break;
332 }
333
334 /*
335 * Consume leading white space, except for formats
336 * that suppress this.
337 */
338 if ((flags & NOSKIP) == 0) {
339 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
340 iswspace(wi))
341 nread++;
342 if (wi == WEOF)
343 goto input_failure;
344 __ungetwc(wi, fp);
345 }
346
347 /*
348 * Do the conversion.
349 */
350 switch (c) {
351
352 case CT_CHAR:
353 /* scan arbitrary characters (sets NOSKIP) */
354 if (width == 0)
355 width = 1;
356 if (flags & LONG) {
357 if (!(flags & SUPPRESS))
358 p = va_arg(ap, wchar_t *);
359 n = 0;
360 while (width-- != 0 &&
361 (wi = __fgetwc_unlock(fp)) != WEOF) {
362 if (!(flags & SUPPRESS))
363 *p++ = (wchar_t)wi;
364 n++;
365 }
366 if (n == 0)
367 goto input_failure;
368 nread += n;
369 if (!(flags & SUPPRESS))
370 nassigned++;
371 } else {
372 if (!(flags & SUPPRESS))
373 mbp = va_arg(ap, char *);
374 n = 0;
375 bzero(&mbs, sizeof(mbs));
376 while (width != 0 &&
377 (wi = __fgetwc_unlock(fp)) != WEOF) {
378 if (width >= MB_CUR_MAX &&
379 !(flags & SUPPRESS)) {
380 nconv = wcrtomb(mbp, wi, &mbs);
381 if (nconv == (size_t)-1)
382 goto input_failure;
383 } else {
384 nconv = wcrtomb(mbbuf, wi,
385 &mbs);
386 if (nconv == (size_t)-1)
387 goto input_failure;
388 if (nconv > width) {
389 __ungetwc(wi, fp);
390 break;
391 }
392 if (!(flags & SUPPRESS))
393 memcpy(mbp, mbbuf,
394 nconv);
395 }
396 if (!(flags & SUPPRESS))
397 mbp += nconv;
398 width -= nconv;
399 n++;
400 }
401 if (n == 0)
402 goto input_failure;
403 nread += n;
404 if (!(flags & SUPPRESS))
405 nassigned++;
406 }
407 nconversions++;
408 break;
409
410 case CT_CCL:
411 /* scan a (nonempty) character class (sets NOSKIP) */
412 if (width == 0)
413 width = (size_t)~0; /* `infinity' */
414 /* take only those things in the class */
415 if ((flags & SUPPRESS) && (flags & LONG)) {
416 n = 0;
417 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
418 width-- != 0 && INCCL(wi))
419 n++;
420 if (wi != WEOF)
421 __ungetwc(wi, fp);
422 if (n == 0)
423 goto match_failure;
424 } else if (flags & LONG) {
425 p0 = p = va_arg(ap, wchar_t *);
426 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
427 width-- != 0 && INCCL(wi))
428 *p++ = (wchar_t)wi;
429 if (wi != WEOF)
430 __ungetwc(wi, fp);
431 n = p - p0;
432 if (n == 0)
433 goto match_failure;
434 *p = 0;
435 nassigned++;
436 } else {
437 if (!(flags & SUPPRESS))
438 mbp = va_arg(ap, char *);
439 n = 0;
440 bzero(&mbs, sizeof(mbs));
441 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
442 width != 0 && INCCL(wi)) {
443 if (width >= MB_CUR_MAX &&
444 !(flags & SUPPRESS)) {
445 nconv = wcrtomb(mbp, wi, &mbs);
446 if (nconv == (size_t)-1)
447 goto input_failure;
448 } else {
449 nconv = wcrtomb(mbbuf, wi,
450 &mbs);
451 if (nconv == (size_t)-1)
452 goto input_failure;
453 if (nconv > width)
454 break;
455 if (!(flags & SUPPRESS))
456 memcpy(mbp, mbbuf,
457 nconv);
458 }
459 if (!(flags & SUPPRESS))
460 mbp += nconv;
461 width -= nconv;
462 n++;
463 }
464 if (wi != WEOF)
465 __ungetwc(wi, fp);
466 if (!(flags & SUPPRESS)) {
467 *mbp = 0;
468 nassigned++;
469 }
470 }
471 nread += n;
472 nconversions++;
473 break;
474
475 case CT_STRING:
476 /* like CCL, but zero-length string OK, & no NOSKIP */
477 if (width == 0)
478 width = (size_t)~0;
479 if ((flags & SUPPRESS) && (flags & LONG)) {
480 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
481 width-- != 0 &&
482 !iswspace(wi))
483 nread++;
484 if (wi != WEOF)
485 __ungetwc(wi, fp);
486 } else if (flags & LONG) {
487 p0 = p = va_arg(ap, wchar_t *);
488 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
489 width-- != 0 &&
490 !iswspace(wi)) {
491 *p++ = (wchar_t)wi;
492 nread++;
493 }
494 if (wi != WEOF)
495 __ungetwc(wi, fp);
496 *p = 0;
497 nassigned++;
498 } else {
499 if (!(flags & SUPPRESS))
500 mbp = va_arg(ap, char *);
501 bzero(&mbs, sizeof(mbs));
502 while ((wi = __fgetwc_unlock(fp)) != WEOF &&
503 width != 0 &&
504 !iswspace(wi)) {
505 if (width >= MB_CUR_MAX &&
506 !(flags & SUPPRESS)) {
507 nconv = wcrtomb(mbp, wi, &mbs);
508 if (nconv == (size_t)-1)
509 goto input_failure;
510 } else {
511 nconv = wcrtomb(mbbuf, wi,
512 &mbs);
513 if (nconv == (size_t)-1)
514 goto input_failure;
515 if (nconv > width)
516 break;
517 if (!(flags & SUPPRESS))
518 memcpy(mbp, mbbuf,
519 nconv);
520 }
521 if (!(flags & SUPPRESS))
522 mbp += nconv;
523 width -= nconv;
524 nread++;
525 }
526 if (wi != WEOF)
527 __ungetwc(wi, fp);
528 if (!(flags & SUPPRESS)) {
529 *mbp = 0;
530 nassigned++;
531 }
532 }
533 nconversions++;
534 continue;
535
536 case CT_INT:
537 /* scan an integer as if by strtoimax/strtoumax */
538 if (width == 0 || width > sizeof(buf) /
539 sizeof(*buf) - 1)
540 width = sizeof(buf) / sizeof(*buf) - 1;
541 flags |= SIGNOK | NDIGITS | NZDIGITS;
542 for (p = buf; width; width--) {
543 c = __fgetwc_unlock(fp);
544 /*
545 * Switch on the character; `goto ok'
546 * if we accept it as a part of number.
547 */
548 switch (c) {
549
550 /*
551 * The digit 0 is always legal, but is
552 * special. For %i conversions, if no
553 * digits (zero or nonzero) have been
554 * scanned (only signs), we will have
555 * base==0. In that case, we should set
556 * it to 8 and enable 0x prefixing.
557 * Also, if we have not scanned zero digits
558 * before this, do not turn off prefixing
559 * (someone else will turn it off if we
560 * have scanned any nonzero digits).
561 */
562 case '0':
563 if (base == 0) {
564 base = 8;
565 flags |= PFXOK;
566 }
567 if (flags & NZDIGITS)
568 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
569 else
570 flags &= ~(SIGNOK|PFXOK|NDIGITS);
571 goto ok;
572
573 /* 1 through 7 always legal */
574 case '1': case '2': case '3':
575 case '4': case '5': case '6': case '7':
576 base = basefix[base];
577 flags &= ~(SIGNOK | PFXOK | NDIGITS);
578 goto ok;
579
580 /* digits 8 and 9 ok iff decimal or hex */
581 case '8': case '9':
582 base = basefix[base];
583 if (base <= 8)
584 break; /* not legal here */
585 flags &= ~(SIGNOK | PFXOK | NDIGITS);
586 goto ok;
587
588 /* letters ok iff hex */
589 case 'A': case 'B': case 'C':
590 case 'D': case 'E': case 'F':
591 case 'a': case 'b': case 'c':
592 case 'd': case 'e': case 'f':
593 /* no need to fix base here */
594 if (base <= 10)
595 break; /* not legal here */
596 flags &= ~(SIGNOK | PFXOK | NDIGITS);
597 goto ok;
598
599 /* sign ok only as first character */
600 case '+': case '-':
601 if (flags & SIGNOK) {
602 flags &= ~SIGNOK;
603 flags |= HAVESIGN;
604 goto ok;
605 }
606 break;
607
608 /*
609 * x ok iff flag still set and 2nd char (or
610 * 3rd char if we have a sign).
611 */
612 case 'x': case 'X':
613 if ((flags & PFXOK) && p ==
614 buf + 1 + !!(flags & HAVESIGN)) {
615 base = 16; /* if %i */
616 flags &= ~PFXOK;
617 goto ok;
618 }
619 break;
620 }
621
622 /*
623 * If we got here, c is not a legal character
624 * for a number. Stop accumulating digits.
625 */
626 if (c != WEOF)
627 __ungetwc(c, fp);
628 break;
629 ok:
630 /*
631 * c is legal: store it and look at the next.
632 */
633 *p++ = (wchar_t)c;
634 }
635 /*
636 * If we had only a sign, it is no good; push
637 * back the sign. If the number ends in `x',
638 * it was [sign] '0' 'x', so push back the x
639 * and treat it as [sign] '0'.
640 */
641 if (flags & NDIGITS) {
642 if (p > buf)
643 __ungetwc(*--p, fp);
644 goto match_failure;
645 }
646 c = p[-1];
647 if (c == 'x' || c == 'X') {
648 --p;
649 __ungetwc(c, fp);
650 }
651 if ((flags & SUPPRESS) == 0) {
652 uintmax_t res;
653
654 *p = '\0';
655 if (flags & UNSIGNED)
656 res = wcstoimax(buf, NULL, base);
657 else
658 res = wcstoumax(buf, NULL, base);
659 if (flags & POINTER)
660 *va_arg(ap, void **) =
661 (void *)(uintptr_t)res;
662 else if (flags & MAXINT)
663 *va_arg(ap, intmax_t *) = res;
664 else if (flags & LLONG)
665 *va_arg(ap, long long *) = res;
666 else if (flags & SIZEINT)
667 *va_arg(ap, ssize_t *) = res;
668 else if (flags & PTRINT)
669 *va_arg(ap, ptrdiff_t *) = res;
670 else if (flags & LONG)
671 *va_arg(ap, long *) = res;
672 else if (flags & SHORT)
673 *va_arg(ap, short *) = res;
674 else if (flags & SHORTSHORT)
675 *va_arg(ap, signed char *) = res;
676 else
677 *va_arg(ap, int *) = res;
678 nassigned++;
679 }
680 nread += p - buf;
681 nconversions++;
682 break;
683
684 #ifdef FLOATING_POINT
685 case CT_FLOAT:
686 /* scan a floating point number as if by strtod */
687 if (width == 0 || width > sizeof(buf) /
688 sizeof(*buf) - 1)
689 width = sizeof(buf) / sizeof(*buf) - 1;
690 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
691 for (p = buf; width; width--) {
692 c = __fgetwc_unlock(fp);
693 /*
694 * This code mimics the integer conversion
695 * code, but is much simpler.
696 */
697 switch (c) {
698
699 case '0': case '1': case '2': case '3':
700 case '4': case '5': case '6': case '7':
701 case '8': case '9':
702 flags &= ~(SIGNOK | NDIGITS);
703 goto fok;
704
705 case '+': case '-':
706 if (flags & SIGNOK) {
707 flags &= ~SIGNOK;
708 goto fok;
709 }
710 break;
711 case 'e': case 'E':
712 /* no exponent without some digits */
713 if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
714 flags =
715 (flags & ~(EXPOK|DPTOK)) |
716 SIGNOK | NDIGITS;
717 goto fok;
718 }
719 break;
720 default:
721 if (decimal_point == 0) {
722 bzero(&mbs, sizeof(mbs));
723 nconv = mbrtowc(&decimal_point,
724 localeconv()->decimal_point,
725 MB_CUR_MAX, &mbs);
726 if (nconv == 0 ||
727 nconv == (size_t)-1 ||
728 nconv == (size_t)-2)
729 decimal_point = '.';
730 }
731 if (c == decimal_point &&
732 (flags & DPTOK)) {
733 flags &= ~(SIGNOK | DPTOK);
734 goto fok;
735 }
736 break;
737 }
738 if (c != WEOF)
739 __ungetwc(c, fp);
740 break;
741 fok:
742 *p++ = c;
743 }
744 /*
745 * If no digits, might be missing exponent digits
746 * (just give back the exponent) or might be missing
747 * regular digits, but had sign and/or decimal point.
748 */
749 if (flags & NDIGITS) {
750 if (flags & EXPOK) {
751 /* no digits at all */
752 while (p > buf)
753 __ungetwc(*--p, fp);
754 goto match_failure;
755 }
756 /* just a bad exponent (e and maybe sign) */
757 c = *--p;
758 if (c != 'e' && c != 'E') {
759 __ungetwc(c, fp);/* sign */
760 c = *--p;
761 }
762 __ungetwc(c, fp);
763 }
764 if ((flags & SUPPRESS) == 0) {
765 *p = 0;
766 if (flags & LONGDBL) {
767 long double res = wcstold(buf, NULL);
768 *va_arg(ap, long double *) = res;
769 } else if (flags & LONG) {
770 double res = wcstod(buf, NULL);
771 *va_arg(ap, double *) = res;
772 } else {
773 float res = wcstof(buf, NULL);
774 *va_arg(ap, float *) = res;
775 }
776 nassigned++;
777 }
778 nread += p - buf;
779 nconversions++;
780 break;
781 #endif /* FLOATING_POINT */
782 }
783 }
784 input_failure:
785 return (nconversions != 0 ? nassigned : EOF);
786 match_failure:
787 return (nassigned);
788 }
789
790 int
vfwscanf(FILE * __restrict fp,const wchar_t * __restrict fmt,__va_list ap)791 vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap)
792 {
793 int r;
794
795 FLOCKFILE(fp);
796 r = __vfwscanf(fp, fmt, ap);
797 FUNLOCKFILE(fp);
798 return (r);
799 }
800 DEF_STRONG(vfwscanf);
801