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

Line Branch Exec Source
1
/*	$OpenBSD: vfscanf.c,v 1.34 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 <ctype.h>
35
#include <wctype.h>
36
#include <inttypes.h>
37
#include <stdarg.h>
38
#include <stddef.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include "local.h"
43
44
#ifdef FLOATING_POINT
45
#include <float.h>
46
#include "floatio.h"
47
#endif
48
49
#define	BUF		513	/* Maximum length of numeric string. */
50
51
/*
52
 * Flags used during conversion.
53
 */
54
#define	LONG		0x00001	/* l: long or double */
55
#define	LONGDBL		0x00002	/* L: long double */
56
#define	SHORT		0x00004	/* h: short */
57
#define	SHORTSHORT	0x00008	/* hh: 8 bit integer */
58
#define LLONG		0x00010	/* ll: long long (+ deprecated q: quad) */
59
#define	POINTER		0x00020	/* p: void * (as hex) */
60
#define	SIZEINT		0x00040	/* z: (signed) size_t */
61
#define	MAXINT		0x00080	/* j: intmax_t */
62
#define	PTRINT		0x00100	/* t: ptrdiff_t */
63
#define	NOSKIP		0x00200	/* [ or c: do not skip blanks */
64
#define	SUPPRESS	0x00400	/* *: suppress assignment */
65
#define	UNSIGNED	0x00800	/* %[oupxX] conversions */
66
67
/*
68
 * The following are used in numeric conversions only:
69
 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
70
 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
71
 */
72
#define	SIGNOK		0x01000	/* +/- is (still) legal */
73
#define	HAVESIGN	0x02000	/* sign detected */
74
#define	NDIGITS		0x04000	/* no digits detected */
75
76
#define	DPTOK		0x08000	/* (float) decimal point is still legal */
77
#define	EXPOK		0x10000	/* (float) exponent (e+3, etc) still legal */
78
79
#define	PFXOK		0x08000	/* 0x prefix is (still) legal */
80
#define	NZDIGITS	0x10000	/* no zero digits detected */
81
82
/*
83
 * Conversion types.
84
 */
85
#define	CT_CHAR		0	/* %c conversion */
86
#define	CT_CCL		1	/* %[...] conversion */
87
#define	CT_STRING	2	/* %s conversion */
88
#define	CT_INT		3	/* integer, i.e., strtoimax or strtoumax */
89
#define	CT_FLOAT	4	/* floating, i.e., strtod */
90
91
#define u_char unsigned char
92
#define u_long unsigned long
93
94
static u_char *__sccl(char *, u_char *);
95
96
/*
97
 * Internal, unlocked version of vfscanf
98
 */
99
int
100
__svfscanf(FILE *fp, const char *fmt0, __va_list ap)
101
{
102
	u_char *fmt = (u_char *)fmt0;
103
	int c;		/* character from format, or conversion */
104
	size_t width;	/* field width, or 0 */
105
	char *p;	/* points into all kinds of strings */
106
	int n;		/* handy integer */
107
	int flags;	/* flags as defined above */
108
	char *p0;	/* saves original value of p when necessary */
109
	int nassigned;		/* number of fields assigned */
110
	int nread;		/* number of characters consumed from fp */
111
	int base;		/* base argument to strtoimax/strtouimax */
112
	char ccltab[256];	/* character class table for %[...] */
113
	char buf[BUF];		/* buffer for numeric conversions */
114
#ifdef SCANF_WIDE_CHAR
115
	wchar_t *wcp;		/* handy wide character pointer */
116
	size_t nconv;		/* length of multibyte sequence converted */
117
	mbstate_t mbs;
118
#endif
119
120
	/* `basefix' is used to avoid `if' tests in the integer scanner */
121
	static short basefix[17] =
122
		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
123
124
	_SET_ORIENTATION(fp, -1);
125
126
	nassigned = 0;
127
	nread = 0;
128
	base = 0;		/* XXX just to keep gcc happy */
129
	for (;;) {
130
		c = *fmt++;
131
		if (c == 0)
132
			return (nassigned);
133
		if (isspace(c)) {
134
			while ((fp->_r > 0 || __srefill(fp) == 0) &&
135
			    isspace(*fp->_p))
136
				nread++, fp->_r--, fp->_p++;
137
			continue;
138
		}
139
		if (c != '%')
140
			goto literal;
141
		width = 0;
142
		flags = 0;
143
		/*
144
		 * switch on the format.  continue if done;
145
		 * break once format type is derived.
146
		 */
147
again:		c = *fmt++;
148
		switch (c) {
149
		case '%':
150
literal:
151
			if (fp->_r <= 0 && __srefill(fp))
152
				goto input_failure;
153
			if (*fp->_p != c)
154
				goto match_failure;
155
			fp->_r--, fp->_p++;
156
			nread++;
157
			continue;
158
159
		case '*':
160
			flags |= SUPPRESS;
161
			goto again;
162
		case 'j':
163
			flags |= MAXINT;
164
			goto again;
165
		case 'L':
166
			flags |= LONGDBL;
167
			goto again;
168
		case 'h':
169
			if (*fmt == 'h') {
170
				fmt++;
171
				flags |= SHORTSHORT;
172
			} else {
173
				flags |= SHORT;
174
			}
175
			goto again;
176
		case 'l':
177
			if (*fmt == 'l') {
178
				fmt++;
179
				flags |= LLONG;
180
			} else {
181
				flags |= LONG;
182
			}
183
			goto again;
184
		case 'q':
185
			flags |= LLONG;		/* deprecated */
186
			goto again;
187
		case 't':
188
			flags |= PTRINT;
189
			goto again;
190
		case 'z':
191
			flags |= SIZEINT;
192
			goto again;
193
194
		case '0': case '1': case '2': case '3': case '4':
195
		case '5': case '6': case '7': case '8': case '9':
196
			width = width * 10 + c - '0';
197
			goto again;
198
199
		/*
200
		 * Conversions.
201
		 * Those marked `compat' are for 4.[123]BSD compatibility.
202
		 *
203
		 * (According to ANSI, E and X formats are supposed
204
		 * to the same as e and x.  Sorry about that.)
205
		 */
206
		case 'D':	/* compat */
207
			flags |= LONG;
208
			/* FALLTHROUGH */
209
		case 'd':
210
			c = CT_INT;
211
			base = 10;
212
			break;
213
214
		case 'i':
215
			c = CT_INT;
216
			base = 0;
217
			break;
218
219
		case 'O':	/* compat */
220
			flags |= LONG;
221
			/* FALLTHROUGH */
222
		case 'o':
223
			c = CT_INT;
224
			flags |= UNSIGNED;
225
			base = 8;
226
			break;
227
228
		case 'u':
229
			c = CT_INT;
230
			flags |= UNSIGNED;
231
			base = 10;
232
			break;
233
234
		case 'X':
235
		case 'x':
236
			flags |= PFXOK;	/* enable 0x prefixing */
237
			c = CT_INT;
238
			flags |= UNSIGNED;
239
			base = 16;
240
			break;
241
242
#ifdef FLOATING_POINT
243
		case 'e': case 'E':
244
		case 'f': case 'F':
245
		case 'g': case 'G':
246
		case 'a': case 'A':
247
			c = CT_FLOAT;
248
			break;
249
#endif
250
251
		case 's':
252
			c = CT_STRING;
253
			break;
254
255
		case '[':
256
			fmt = __sccl(ccltab, fmt);
257
			flags |= NOSKIP;
258
			c = CT_CCL;
259
			break;
260
261
		case 'c':
262
			flags |= NOSKIP;
263
			c = CT_CHAR;
264
			break;
265
266
		case 'p':	/* pointer format is like hex */
267
			flags |= POINTER | PFXOK;
268
			c = CT_INT;
269
			flags |= UNSIGNED;
270
			base = 16;
271
			break;
272
273
		case 'n':
274
			if (flags & SUPPRESS)
275
				continue;
276
			if (flags & SHORTSHORT)
277
				*va_arg(ap, signed char *) = nread;
278
			else if (flags & SHORT)
279
				*va_arg(ap, short *) = nread;
280
			else if (flags & LONG)
281
				*va_arg(ap, long *) = nread;
282
			else if (flags & SIZEINT)
283
				*va_arg(ap, ssize_t *) = nread;
284
			else if (flags & PTRINT)
285
				*va_arg(ap, ptrdiff_t *) = nread;
286
			else if (flags & LLONG)
287
				*va_arg(ap, long long *) = nread;
288
			else if (flags & MAXINT)
289
				*va_arg(ap, intmax_t *) = nread;
290
			else
291
				*va_arg(ap, int *) = nread;
292
			continue;
293
294
		/*
295
		 * Disgusting backwards compatibility hacks.	XXX
296
		 */
297
		case '\0':	/* compat */
298
			return (EOF);
299
300
		default:	/* compat */
301
			if (isupper(c))
302
				flags |= LONG;
303
			c = CT_INT;
304
			base = 10;
305
			break;
306
		}
307
308
		/*
309
		 * We have a conversion that requires input.
310
		 */
311
		if (fp->_r <= 0 && __srefill(fp))
312
			goto input_failure;
313
314
		/*
315
		 * Consume leading white space, except for formats
316
		 * that suppress this.
317
		 */
318
		if ((flags & NOSKIP) == 0) {
319
			while (isspace(*fp->_p)) {
320
				nread++;
321
				if (--fp->_r > 0)
322
					fp->_p++;
323
				else if (__srefill(fp))
324
					goto input_failure;
325
			}
326
			/*
327
			 * Note that there is at least one character in
328
			 * the buffer, so conversions that do not set NOSKIP
329
			 * ca no longer result in an input failure.
330
			 */
331
		}
332
333
		/*
334
		 * Do the conversion.
335
		 */
336
		switch (c) {
337
338
		case CT_CHAR:
339
			/* scan arbitrary characters (sets NOSKIP) */
340
			if (width == 0)
341
				width = 1;
342
#ifdef SCANF_WIDE_CHAR
343
			if (flags & LONG) {
344
				if ((flags & SUPPRESS) == 0)
345
					wcp = va_arg(ap, wchar_t *);
346
				else
347
					wcp = NULL;
348
				n = 0;
349
				while (width != 0) {
350
					if (n == MB_CUR_MAX) {
351
						fp->_flags |= __SERR;
352
						goto input_failure;
353
					}
354
					buf[n++] = *fp->_p;
355
					fp->_p++;
356
					fp->_r--;
357
					bzero(&mbs, sizeof(mbs));
358
					nconv = mbrtowc(wcp, buf, n, &mbs);
359
					if (nconv == (size_t)-1) {
360
						fp->_flags |= __SERR;
361
						goto input_failure;
362
					}
363
					if (nconv == 0 && !(flags & SUPPRESS))
364
						*wcp = L'\0';
365
					if (nconv != (size_t)-2) {
366
						nread += n;
367
						width--;
368
						if (!(flags & SUPPRESS))
369
							wcp++;
370
						n = 0;
371
					}
372
					if (fp->_r <= 0 && __srefill(fp)) {
373
						if (n != 0) {
374
							fp->_flags |= __SERR;
375
							goto input_failure;
376
						}
377
						break;
378
					}
379
				}
380
				if (!(flags & SUPPRESS))
381
					nassigned++;
382
			} else
383
#endif /* SCANF_WIDE_CHAR */
384
			if (flags & SUPPRESS) {
385
				size_t sum = 0;
386
				for (;;) {
387
					if ((n = fp->_r) < width) {
388
						sum += n;
389
						width -= n;
390
						fp->_p += n;
391
						if (__srefill(fp)) {
392
							if (sum == 0)
393
							    goto input_failure;
394
							break;
395
						}
396
					} else {
397
						sum += width;
398
						fp->_r -= width;
399
						fp->_p += width;
400
						break;
401
					}
402
				}
403
				nread += sum;
404
			} else {
405
				size_t r = fread(va_arg(ap, char *), 1,
406
				    width, fp);
407
408
				if (r == 0)
409
					goto input_failure;
410
				nread += r;
411
				nassigned++;
412
			}
413
			break;
414
415
		case CT_CCL:
416
			/* scan a (nonempty) character class (sets NOSKIP) */
417
			if (width == 0)
418
				width = (size_t)~0;	/* `infinity' */
419
#ifdef SCANF_WIDE_CHAR
420
			/* take only those things in the class */
421
			if (flags & LONG) {
422
				wchar_t twc;
423
				int nchars;
424
425
				if ((flags & SUPPRESS) == 0)
426
					wcp = va_arg(ap, wchar_t *);
427
				else
428
					wcp = &twc;
429
				n = 0;
430
				nchars = 0;
431
				while (width != 0) {
432
					if (n == MB_CUR_MAX) {
433
						fp->_flags |= __SERR;
434
						goto input_failure;
435
					}
436
					buf[n++] = *fp->_p;
437
					fp->_p++;
438
					fp->_r--;
439
					bzero(&mbs, sizeof(mbs));
440
					nconv = mbrtowc(wcp, buf, n, &mbs);
441
					if (nconv == (size_t)-1) {
442
						fp->_flags |= __SERR;
443
						goto input_failure;
444
					}
445
					if (nconv == 0)
446
						*wcp = L'\0';
447
					if (nconv != (size_t)-2) {
448
						if (wctob(*wcp) != EOF &&
449
						    !ccltab[wctob(*wcp)]) {
450
							while (n != 0) {
451
								n--;
452
								ungetc(buf[n],
453
								    fp);
454
							}
455
							break;
456
						}
457
						nread += n;
458
						width--;
459
						if (!(flags & SUPPRESS))
460
							wcp++;
461
						nchars++;
462
						n = 0;
463
					}
464
					if (fp->_r <= 0 && __srefill(fp)) {
465
						if (n != 0) {
466
							fp->_flags |= __SERR;
467
							goto input_failure;
468
						}
469
						break;
470
					}
471
				}
472
				if (n != 0) {
473
					fp->_flags |= __SERR;
474
					goto input_failure;
475
				}
476
				n = nchars;
477
				if (n == 0)
478
					goto match_failure;
479
				if (!(flags & SUPPRESS)) {
480
					*wcp = L'\0';
481
					nassigned++;
482
				}
483
			} else
484
#endif /* SCANF_WIDE_CHAR */
485
			/* take only those things in the class */
486
			if (flags & SUPPRESS) {
487
				n = 0;
488
				while (ccltab[*fp->_p]) {
489
					n++, fp->_r--, fp->_p++;
490
					if (--width == 0)
491
						break;
492
					if (fp->_r <= 0 && __srefill(fp)) {
493
						if (n == 0)
494
							goto input_failure;
495
						break;
496
					}
497
				}
498
				if (n == 0)
499
					goto match_failure;
500
			} else {
501
				p0 = p = va_arg(ap, char *);
502
				while (ccltab[*fp->_p]) {
503
					fp->_r--;
504
					*p++ = *fp->_p++;
505
					if (--width == 0)
506
						break;
507
					if (fp->_r <= 0 && __srefill(fp)) {
508
						if (p == p0)
509
							goto input_failure;
510
						break;
511
					}
512
				}
513
				n = p - p0;
514
				if (n == 0)
515
					goto match_failure;
516
				*p = '\0';
517
				nassigned++;
518
			}
519
			nread += n;
520
			break;
521
522
		case CT_STRING:
523
			/* like CCL, but zero-length string OK, & no NOSKIP */
524
			if (width == 0)
525
				width = (size_t)~0;
526
#ifdef SCANF_WIDE_CHAR
527
			if (flags & LONG) {
528
				wchar_t twc;
529
530
				if ((flags & SUPPRESS) == 0)
531
					wcp = va_arg(ap, wchar_t *);
532
				else
533
					wcp = &twc;
534
				n = 0;
535
				while (!isspace(*fp->_p) && width != 0) {
536
					if (n == MB_CUR_MAX) {
537
						fp->_flags |= __SERR;
538
						goto input_failure;
539
					}
540
					buf[n++] = *fp->_p;
541
					fp->_p++;
542
					fp->_r--;
543
					bzero(&mbs, sizeof(mbs));
544
					nconv = mbrtowc(wcp, buf, n, &mbs);
545
					if (nconv == (size_t)-1) {
546
						fp->_flags |= __SERR;
547
						goto input_failure;
548
					}
549
					if (nconv == 0)
550
						*wcp = L'\0';
551
					if (nconv != (size_t)-2) {
552
						if (iswspace(*wcp)) {
553
							while (n != 0) {
554
								n--;
555
								ungetc(buf[n],
556
								    fp);
557
							}
558
							break;
559
						}
560
						nread += n;
561
						width--;
562
						if (!(flags & SUPPRESS))
563
							wcp++;
564
						n = 0;
565
					}
566
					if (fp->_r <= 0 && __srefill(fp)) {
567
						if (n != 0) {
568
							fp->_flags |= __SERR;
569
							goto input_failure;
570
						}
571
						break;
572
					}
573
				}
574
				if (!(flags & SUPPRESS)) {
575
					*wcp = L'\0';
576
					nassigned++;
577
				}
578
			} else
579
#endif /* SCANF_WIDE_CHAR */
580
			if (flags & SUPPRESS) {
581
				n = 0;
582
				while (!isspace(*fp->_p)) {
583
					n++, fp->_r--, fp->_p++;
584
					if (--width == 0)
585
						break;
586
					if (fp->_r <= 0 && __srefill(fp))
587
						break;
588
				}
589
				nread += n;
590
			} else {
591
				p0 = p = va_arg(ap, char *);
592
				while (!isspace(*fp->_p)) {
593
					fp->_r--;
594
					*p++ = *fp->_p++;
595
					if (--width == 0)
596
						break;
597
					if (fp->_r <= 0 && __srefill(fp))
598
						break;
599
				}
600
				*p = '\0';
601
				nread += p - p0;
602
				nassigned++;
603
			}
604
			continue;
605
606
		case CT_INT:
607
			/* scan an integer as if by strtoimax/strtoumax */
608
#ifdef hardway
609
			if (width == 0 || width > sizeof(buf) - 1)
610
				width = sizeof(buf) - 1;
611
#else
612
			/* size_t is unsigned, hence this optimisation */
613
			if (--width > sizeof(buf) - 2)
614
				width = sizeof(buf) - 2;
615
			width++;
616
#endif
617
			flags |= SIGNOK | NDIGITS | NZDIGITS;
618
			for (p = buf; width; width--) {
619
				c = *fp->_p;
620
				/*
621
				 * Switch on the character; `goto ok'
622
				 * if we accept it as a part of number.
623
				 */
624
				switch (c) {
625
626
				/*
627
				 * The digit 0 is always legal, but is
628
				 * special.  For %i conversions, if no
629
				 * digits (zero or nonzero) have been
630
				 * scanned (only signs), we will have
631
				 * base==0.  In that case, we should set
632
				 * it to 8 and enable 0x prefixing.
633
				 * Also, if we have not scanned zero digits
634
				 * before this, do not turn off prefixing
635
				 * (someone else will turn it off if we
636
				 * have scanned any nonzero digits).
637
				 */
638
				case '0':
639
					if (base == 0) {
640
						base = 8;
641
						flags |= PFXOK;
642
					}
643
					if (flags & NZDIGITS)
644
					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
645
					else
646
					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
647
					goto ok;
648
649
				/* 1 through 7 always legal */
650
				case '1': case '2': case '3':
651
				case '4': case '5': case '6': case '7':
652
					base = basefix[base];
653
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
654
					goto ok;
655
656
				/* digits 8 and 9 ok iff decimal or hex */
657
				case '8': case '9':
658
					base = basefix[base];
659
					if (base <= 8)
660
						break;	/* not legal here */
661
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
662
					goto ok;
663
664
				/* letters ok iff hex */
665
				case 'A': case 'B': case 'C':
666
				case 'D': case 'E': case 'F':
667
				case 'a': case 'b': case 'c':
668
				case 'd': case 'e': case 'f':
669
					/* no need to fix base here */
670
					if (base <= 10)
671
						break;	/* not legal here */
672
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
673
					goto ok;
674
675
				/* sign ok only as first character */
676
				case '+': case '-':
677
					if (flags & SIGNOK) {
678
						flags &= ~SIGNOK;
679
						flags |= HAVESIGN;
680
						goto ok;
681
					}
682
					break;
683
684
				/*
685
				 * x ok iff flag still set and 2nd char (or
686
				 * 3rd char if we have a sign).
687
				 */
688
				case 'x': case 'X':
689
					if ((flags & PFXOK) && p ==
690
					    buf + 1 + !!(flags & HAVESIGN)) {
691
						base = 16;	/* if %i */
692
						flags &= ~PFXOK;
693
						goto ok;
694
					}
695
					break;
696
				}
697
698
				/*
699
				 * If we got here, c is not a legal character
700
				 * for a number.  Stop accumulating digits.
701
				 */
702
				break;
703
		ok:
704
				/*
705
				 * c is legal: store it and look at the next.
706
				 */
707
				*p++ = c;
708
				if (--fp->_r > 0)
709
					fp->_p++;
710
				else if (__srefill(fp))
711
					break;		/* EOF */
712
			}
713
			/*
714
			 * If we had only a sign, it is no good; push
715
			 * back the sign.  If the number ends in `x',
716
			 * it was [sign] '0' 'x', so push back the x
717
			 * and treat it as [sign] '0'.
718
			 */
719
			if (flags & NDIGITS) {
720
				if (p > buf)
721
					(void) ungetc(*(u_char *)--p, fp);
722
				goto match_failure;
723
			}
724
			c = ((u_char *)p)[-1];
725
			if (c == 'x' || c == 'X') {
726
				--p;
727
				(void) ungetc(c, fp);
728
			}
729
			if ((flags & SUPPRESS) == 0) {
730
				uintmax_t res;
731
732
				*p = '\0';
733
				if (flags & UNSIGNED)
734
					res = strtoumax(buf, NULL, base);
735
				else
736
					res = strtoimax(buf, NULL, base);
737
				if (flags & POINTER)
738
					*va_arg(ap, void **) =
739
					    (void *)(uintptr_t)res;
740
				else if (flags & MAXINT)
741
					*va_arg(ap, intmax_t *) = res;
742
				else if (flags & LLONG)
743
					*va_arg(ap, long long *) = res;
744
				else if (flags & SIZEINT)
745
					*va_arg(ap, ssize_t *) = res;
746
				else if (flags & PTRINT)
747
					*va_arg(ap, ptrdiff_t *) = res;
748
				else if (flags & LONG)
749
					*va_arg(ap, long *) = res;
750
				else if (flags & SHORT)
751
					*va_arg(ap, short *) = res;
752
				else if (flags & SHORTSHORT)
753
					*va_arg(ap, signed char *) = res;
754
				else
755
					*va_arg(ap, int *) = res;
756
				nassigned++;
757
			}
758
			nread += p - buf;
759
			break;
760
761
#ifdef FLOATING_POINT
762
		case CT_FLOAT:
763
			/* scan a floating point number as if by strtod */
764
#ifdef hardway
765
			if (width == 0 || width > sizeof(buf) - 1)
766
				width = sizeof(buf) - 1;
767
#else
768
			/* size_t is unsigned, hence this optimisation */
769
			if (--width > sizeof(buf) - 2)
770
				width = sizeof(buf) - 2;
771
			width++;
772
#endif
773
			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
774
			for (p = buf; width; width--) {
775
				c = *fp->_p;
776
				/*
777
				 * This code mimicks the integer conversion
778
				 * code, but is much simpler.
779
				 */
780
				switch (c) {
781
782
				case '0': case '1': case '2': case '3':
783
				case '4': case '5': case '6': case '7':
784
				case '8': case '9':
785
					flags &= ~(SIGNOK | NDIGITS);
786
					goto fok;
787
788
				case '+': case '-':
789
					if (flags & SIGNOK) {
790
						flags &= ~SIGNOK;
791
						goto fok;
792
					}
793
					break;
794
				case '.':
795
					if (flags & DPTOK) {
796
						flags &= ~(SIGNOK | DPTOK);
797
						goto fok;
798
					}
799
					break;
800
				case 'e': case 'E':
801
					/* no exponent without some digits */
802
					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
803
						flags =
804
						    (flags & ~(EXPOK|DPTOK)) |
805
						    SIGNOK | NDIGITS;
806
						goto fok;
807
					}
808
					break;
809
				}
810
				break;
811
		fok:
812
				*p++ = c;
813
				if (--fp->_r > 0)
814
					fp->_p++;
815
				else if (__srefill(fp))
816
					break;	/* EOF */
817
			}
818
			/*
819
			 * If no digits, might be missing exponent digits
820
			 * (just give back the exponent) or might be missing
821
			 * regular digits, but had sign and/or decimal point.
822
			 */
823
			if (flags & NDIGITS) {
824
				if (flags & EXPOK) {
825
					/* no digits at all */
826
					while (p > buf)
827
						ungetc(*(u_char *)--p, fp);
828
					goto match_failure;
829
				}
830
				/* just a bad exponent (e and maybe sign) */
831
				c = *(u_char *)--p;
832
				if (c != 'e' && c != 'E') {
833
					(void) ungetc(c, fp);/* sign */
834
					c = *(u_char *)--p;
835
				}
836
				(void) ungetc(c, fp);
837
			}
838
			if ((flags & SUPPRESS) == 0) {
839
				*p = '\0';
840
				if (flags & LONGDBL) {
841
					long double res = strtold(buf,
842
					    (char **)NULL);
843
					*va_arg(ap, long double *) = res;
844
				} else if (flags & LONG) {
845
					double res = strtod(buf, (char **)NULL);
846
					*va_arg(ap, double *) = res;
847
				} else {
848
					float res = strtof(buf, (char **)NULL);
849
					*va_arg(ap, float *) = res;
850
				}
851
				nassigned++;
852
			}
853
			nread += p - buf;
854
			break;
855
#endif /* FLOATING_POINT */
856
		}
857
	}
858
input_failure:
859
	if (nassigned == 0)
860
		nassigned = -1;
861
match_failure:
862
	return (nassigned);
863
}
864
865
/*
866
 * Fill in the given table from the scanset at the given format
867
 * (just after `[').  Return a pointer to the character past the
868
 * closing `]'.  The table has a 1 wherever characters should be
869
 * considered part of the scanset.
870
 */
871
static u_char *
872
__sccl(char *tab, u_char *fmt)
873
{
874
	int c, n, v;
875
876
	/* first `clear' the whole table */
877
	c = *fmt++;		/* first char hat => negated scanset */
878
	if (c == '^') {
879
		v = 1;		/* default => accept */
880
		c = *fmt++;	/* get new first char */
881
	} else
882
		v = 0;		/* default => reject */
883
	/* should probably use memset here */
884
	for (n = 0; n < 256; n++)
885
		tab[n] = v;
886
	if (c == 0)
887
		return (fmt - 1);/* format ended before closing ] */
888
889
	/*
890
	 * Now set the entries corresponding to the actual scanset
891
	 * to the opposite of the above.
892
	 *
893
	 * The first character may be ']' (or '-') without being special;
894
	 * the last character may be '-'.
895
	 */
896
	v = 1 - v;
897
	for (;;) {
898
		tab[c] = v;		/* take character c */
899
doswitch:
900
		n = *fmt++;		/* and examine the next */
901
		switch (n) {
902
903
		case 0:			/* format ended too soon */
904
			return (fmt - 1);
905
906
		case '-':
907
			/*
908
			 * A scanset of the form
909
			 *	[01+-]
910
			 * is defined as `the digit 0, the digit 1,
911
			 * the character +, the character -', but
912
			 * the effect of a scanset such as
913
			 *	[a-zA-Z0-9]
914
			 * is implementation defined.  The V7 Unix
915
			 * scanf treats `a-z' as `the letters a through
916
			 * z', but treats `a-a' as `the letter a, the
917
			 * character -, and the letter a'.
918
			 *
919
			 * For compatibility, the `-' is not considerd
920
			 * to define a range if the character following
921
			 * it is either a close bracket (required by ANSI)
922
			 * or is not numerically greater than the character
923
			 * we just stored in the table (c).
924
			 */
925
			n = *fmt;
926
			if (n == ']' || n < c) {
927
				c = '-';
928
				break;	/* resume the for(;;) */
929
			}
930
			fmt++;
931
			do {		/* fill in the range */
932
				tab[++c] = v;
933
			} while (c < n);
934
#if 1	/* XXX another disgusting compatibility hack */
935
			/*
936
			 * Alas, the V7 Unix scanf also treats formats
937
			 * such as [a-c-e] as `the letters a through e'.
938
			 * This too is permitted by the standard....
939
			 */
940
			goto doswitch;
941
#else
942
			c = *fmt++;
943
			if (c == 0)
944
				return (fmt - 1);
945
			if (c == ']')
946
				return (fmt);
947
#endif
948
			break;
949
950
		case ']':		/* end of scanset */
951
			return (fmt);
952
953
		default:		/* just another character */
954
			c = n;
955
			break;
956
		}
957
	}
958
	/* NOTREACHED */
959
}
960
961
int
962
vfscanf(FILE *fp, const char *fmt0, __va_list ap)
963
{
964
	int r;
965
966
	FLOCKFILE(fp);
967
	r = __svfscanf(fp, fmt0, ap);
968
	FUNLOCKFILE(fp);
969
	return (r);
970
}
971
DEF_STRONG(vfscanf);