GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/stdio/vfwscanf.c Lines: 0 362 0.0 %
Date: 2017-11-07 Branches: 0 424 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: vfwscanf.c,v 1.6 2016/10/30 05:07:06 jsg 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
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 input_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 mimicks 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
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);