1 /*
2 FUNCTION
3 <<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
4 
5 INDEX
6 	vscanf
7 INDEX
8 	vfscanf
9 INDEX
10 	vsscanf
11 
12 ANSI_SYNOPSIS
13 	#include <stdio.h>
14 	#include <stdarg.h>
15 	int vscanf(const char *restrict <[fmt]>, va_list <[list]>);
16 	int vfscanf(FILE *restrict <[fp]>, const char *restrict <[fmt]>, va_list <[list]>);
17 	int vsscanf(const char *restrict <[str]>, const char *restrict <[fmt]>, va_list <[list]>);
18 
19 	int _vscanf_r(void *<[reent]>, const char *restrict <[fmt]>,
20                        va_list <[list]>);
21 	int _vfscanf_r(void *<[reent]>, FILE *restrict <[fp]>, const char *restrict <[fmt]>,
22                        va_list <[list]>);
23 	int _vsscanf_r(void *<[reent]>, const char *restrict <[str]>, const char *restrict <[fmt]>,
24                        va_list <[list]>);
25 
26 TRAD_SYNOPSIS
27 	#include <stdio.h>
28 	#include <varargs.h>
29 	int vscanf( <[fmt]>, <[ist]>)
30 	char *<[fmt]>;
31 	va_list <[list]>;
32 
33 	int vfscanf( <[fp]>, <[fmt]>, <[list]>)
34 	FILE *<[fp]>;
35 	char *<[fmt]>;
36 	va_list <[list]>;
37 
38 	int vsscanf( <[str]>, <[fmt]>, <[list]>)
39 	char *<[str]>;
40 	char *<[fmt]>;
41 	va_list <[list]>;
42 
43 	int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
44 	char *<[reent]>;
45 	char *<[fmt]>;
46 	va_list <[list]>;
47 
48 	int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
49 	char *<[reent]>;
50 	FILE *<[fp]>;
51 	char *<[fmt]>;
52 	va_list <[list]>;
53 
54 	int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
55 	char *<[reent]>;
56 	char *<[str]>;
57 	char *<[fmt]>;
58 	va_list <[list]>;
59 
60 DESCRIPTION
61 <<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
62 of <<scanf>>, <<fscanf>>, and <<sscanf>>.  They differ only in
63 allowing their caller to pass the variable argument list as a
64 <<va_list>> object (initialized by <<va_start>>) rather than
65 directly accepting a variable number of arguments.
66 
67 RETURNS
68 The return values are consistent with the corresponding functions:
69 <<vscanf>> returns the number of input fields successfully scanned,
70 converted, and stored; the return value does not include scanned
71 fields which were not stored.
72 
73 If <<vscanf>> attempts to read at end-of-file, the return value
74 is <<EOF>>.
75 
76 If no fields were stored, the return value is <<0>>.
77 
78 The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
79 reentrant versions which take an additional first parameter which points to the
80 reentrancy structure.
81 
82 PORTABILITY
83 These are GNU extensions.
84 
85 Supporting OS subroutines required:
86 */
87 
88 /*-
89  * Copyright (c) 1990 The Regents of the University of California.
90  * All rights reserved.
91  *
92  * Redistribution and use in source and binary forms are permitted
93  * provided that the above copyright notice and this paragraph are
94  * duplicated in all such forms and that any documentation,
95  * advertising materials, and other materials related to such
96  * distribution and use acknowledge that the software was developed
97  * by the University of California, Berkeley.  The name of the
98  * University may not be used to endorse or promote products derived
99  * from this software without specific prior written permission.
100  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
101  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
102  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
103  */
104 
105 #include <_ansi.h>
106 #include <reent.h>
107 #include <newlib.h>
108 #include <ctype.h>
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <limits.h>
112 #include <wchar.h>
113 #include <string.h>
114 #ifdef _HAVE_STDC
115 #include <stdarg.h>
116 #else
117 #include <varargs.h>
118 #endif
119 #include "local.h"
120 
121 #ifndef	NO_FLOATING_POINT
122 #define FLOATING_POINT
123 #endif
124 
125 #ifdef FLOATING_POINT
126 #include <float.h>
127 
128 /* Currently a test is made to see if long double processing is warranted.
129    This could be changed in the future should the _ldtoa_r code be
130    preferred over _dtoa_r.  */
131 #define _NO_LONGDBL
132 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
133 #undef _NO_LONGDBL
134 #endif
135 
136 #define _NO_LONGLONG
137 #if defined _WANT_IO_LONG_LONG && defined __GNUC__
138 # undef _NO_LONGLONG
139 #endif
140 
141 #include "floatio.h"
142 #define	BUF	(MAXEXP+MAXFRACT+3)	/* 3 = sign + decimal point + NUL */
143 /* An upper bound for how long a long prints in decimal.  4 / 13 approximates
144    log (2).  Add one char for roundoff compensation and one for the sign.  */
145 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long)  - 1) * 4 / 13 + 2)
146 #else
147 #define	BUF	40
148 #endif
149 
150 /*
151  * Flags used during conversion.
152  */
153 
154 #define	LONG		0x01	/* l: long or double */
155 #define	LONGDBL		0x02	/* L: long double or long long */
156 #define	SHORT		0x04	/* h: short */
157 #define	SUPPRESS	0x10	/* suppress assignment */
158 #define	POINTER		0x20	/* weird %p pointer (`fake hex') */
159 #define	NOSKIP		0x40	/* do not skip blanks */
160 
161 /*
162  * The following are used in numeric conversions only:
163  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
164  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
165  */
166 
167 #define	SIGNOK		0x80	/* +/- is (still) legal */
168 #define	NDIGITS		0x100	/* no digits detected */
169 
170 #define	DPTOK		0x200	/* (float) decimal point is still legal */
171 #define	EXPOK		0x400	/* (float) exponent (e+3, etc) still legal */
172 
173 #define	PFXOK		0x200	/* 0x prefix is (still) legal */
174 #define	NZDIGITS	0x400	/* no zero digits detected */
175 #define	NNZDIGITS	0x800	/* no non-zero digits detected */
176 
177 #define	VECTOR		0x2000	/* v: vector */
178 #define	FIXEDPOINT	0x4000	/* r/R: fixed-point */
179 #define	SIGNED  	0x8000	/* r: signed fixed-point */
180 
181 /*
182  * Conversion types.
183  */
184 
185 #define	CT_CHAR		0	/* %c conversion */
186 #define	CT_CCL		1	/* %[...] conversion */
187 #define	CT_STRING	2	/* %s conversion */
188 #define	CT_INT		3	/* integer, i.e., strtol or strtoul */
189 #define	CT_FLOAT	4	/* floating, i.e., strtod */
190 
191 #if 0
192 #define u_char unsigned char
193 #endif
194 #define u_char char
195 #define u_long unsigned long
196 
197 #ifndef _NO_LONGLONG
198 typedef unsigned long long u_long_long;
199 #endif
200 
201 typedef union
202 {
203   char c[16] __attribute__ ((__aligned__ (16)));
204   short h[8];
205   long l[4];
206   int i[4];
207   float f[4];
208 } vec_union;
209 
210 /*
211  * vfscanf
212  */
213 
214 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
215 
216 #ifndef _REENT_ONLY
217 
218 int
219 _DEFUN (vfscanf, (fp, fmt, ap),
220     register FILE *__restrict fp _AND
221     _CONST char *__restrict fmt _AND
222     va_list ap)
223 {
224   CHECK_INIT(_REENT, fp);
225   return __svfscanf_r (_REENT, fp, fmt, ap);
226 }
227 
228 int
__svfscanf(fp,fmt0,ap)229 __svfscanf (fp, fmt0, ap)
230      register FILE *fp;
231      char _CONST *fmt0;
232      va_list ap;
233 {
234   return __svfscanf_r (_REENT, fp, fmt0, ap);
235 }
236 
237 #endif /* !_REENT_ONLY */
238 
239 int
240 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
241     struct _reent *data _AND
242     register FILE *__restrict fp _AND
243     _CONST char *__restrict fmt _AND
244     va_list ap)
245 {
246   return __svfscanf_r (data, fp, fmt, ap);
247 }
248 
249 
250 int
__svfscanf_r(rptr,fp,fmt0,ap)251 __svfscanf_r (rptr, fp, fmt0, ap)
252      struct _reent *rptr;
253      register FILE *fp;
254      char _CONST *fmt0;
255      va_list ap;
256 {
257   register u_char *fmt = (u_char *) fmt0;
258   register int c;		/* character from format, or conversion */
259   register int type;		/* conversion type */
260   register size_t width;	/* field width, or 0 */
261   register char *p;		/* points into all kinds of strings */
262   register int n;		/* handy integer */
263   register int flags;		/* flags as defined above */
264   register char *p0;		/* saves original value of p when necessary */
265   int orig_flags;               /* saved flags used when processing vector */
266   int int_width;                /* tmp area to store width when processing int */
267   int nassigned;		/* number of fields assigned */
268   int nread;			/* number of characters consumed from fp */
269   int base = 0;			/* base argument to strtol/strtoul */
270   int nbytes = 1;               /* number of bytes read from fmt string */
271   wchar_t wc;                   /* wchar to use to read format string */
272   char vec_sep;                 /* vector separator char */
273   char last_space_char;         /* last white-space char eaten - needed for vec support */
274   int vec_read_count;           /* number of vector items to read separately */
275   int looped;                   /* has vector processing looped */
276   u_long (*ccfn) () = 0;	/* conversion function (strtol/strtoul) */
277   char ccltab[256];		/* character class table for %[...] */
278   char buf[BUF];		/* buffer for numeric conversions */
279   vec_union vec_buf;
280   char *lptr;                   /* literal pointer */
281 #ifdef _MB_CAPABLE
282   mbstate_t state;                /* value to keep track of multibyte state */
283 #endif
284 
285   char *ch_dest;
286   short *sp;
287   int *ip;
288   float *flp;
289   _LONG_DOUBLE *ldp;
290   double *dp;
291   long *lp;
292 #ifndef _NO_LONGLONG
293   long long *llp;
294 #else
295 	u_long _uquad;
296 #endif
297 
298   /* `basefix' is used to avoid `if' tests in the integer scanner */
299   static _CONST short basefix[17] =
300     {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
301 
302   nassigned = 0;
303   nread = 0;
304   for (;;)
305     {
306 #ifndef _MB_CAPABLE
307       wc = *fmt;
308 #else
309       memset (&state, '\0', sizeof (state));
310       nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
311 #endif
312       fmt += nbytes;
313       if (wc == 0)
314 	return nassigned;
315       if (nbytes == 1 && isspace (wc))
316 	{
317 	  for (;;)
318 	    {
319 	      if (BufferEmpty)
320 		return nassigned;
321 	      if (!isspace (*fp->_p))
322 		break;
323 	      nread++, fp->_r--, fp->_p++;
324 	    }
325 	  continue;
326 	}
327       if (wc != '%')
328 	goto literal;
329       width = 0;
330       flags = 0;
331       vec_sep = ' ';
332       vec_read_count = 0;
333       looped = 0;
334 
335       /*
336        * switch on the format.  continue if done; break once format
337        * type is derived.
338        */
339 
340     again:
341       c = *fmt++;
342 
343       switch (c)
344 	{
345 	case '%':
346 	literal:
347           lptr = fmt - nbytes;
348           for (n = 0; n < nbytes; ++n)
349             {
350 	      if (BufferEmpty)
351 	        goto input_failure;
352 	      if (*fp->_p != *lptr)
353 	        goto match_failure;
354 	      fp->_r--, fp->_p++;
355 	      nread++;
356               ++lptr;
357             }
358 	  continue;
359 
360 	case '*':
361 	  flags |= SUPPRESS;
362 	  goto again;
363 	case ',':
364 	case ';':
365 	case ':':
366 	case '_':
367 	  if (flags == SUPPRESS || flags == 0)
368 	    vec_sep = c;
369 	  goto again;
370 	case 'l':
371 	  if (flags & SHORT)
372 	    continue; /* invalid format, don't process any further */
373 	  if (flags & LONG)
374 	    {
375 	      flags &= ~LONG;
376 	      flags &= ~VECTOR;
377 	      flags |= LONGDBL;
378 	    }
379 	  else
380 	    {
381 	      flags |= LONG;
382 	      if (flags & VECTOR)
383 		vec_read_count = 4;
384 	    }
385 	  goto again;
386 	case 'L':
387 	  flags |= LONGDBL;
388 	  flags &= ~VECTOR;
389 	  goto again;
390 	case 'h':
391 	  flags |= SHORT;
392 	  if (flags & LONG)
393 	    continue;  /* invalid format, don't process any further */
394 	  if (flags & VECTOR)
395 	    vec_read_count = 8;
396 	  goto again;
397 #ifdef __ALTIVEC__
398 	case 'v':
399 	  flags |= VECTOR;
400 	  vec_read_count = (flags & SHORT) ? 8 : ((flags & LONG) ? 4 : 16);
401 	  goto again;
402 #endif
403 	case '0':
404 	case '1':
405 	case '2':
406 	case '3':
407 	case '4':
408 	case '5':
409 	case '6':
410 	case '7':
411 	case '8':
412 	case '9':
413 	  width = width * 10 + c - '0';
414 	  goto again;
415 
416 	  /*
417 	   * Conversions. Those marked `compat' are for
418 	   * 4.[123]BSD compatibility.
419 	   *
420 	   * (According to ANSI, E and X formats are supposed to
421 	   * the same as e and x.  Sorry about that.)
422 	   */
423 
424 	case 'D':		/* compat */
425 	  flags |= LONG;
426 	  /* FALLTHROUGH */
427 	case 'd':
428 	  type = CT_INT;
429 	  ccfn = (u_long (*)())_strtol_r;
430 	  base = 10;
431 	  break;
432 
433 	case 'i':
434 	  type = CT_INT;
435 	  ccfn = (u_long (*)())_strtol_r;
436 	  base = 0;
437 	  break;
438 
439 	case 'O':		/* compat */
440 	  flags |= LONG;
441 	  /* FALLTHROUGH */
442 	case 'o':
443 	  type = CT_INT;
444 	  ccfn = _strtoul_r;
445 	  base = 8;
446 	  break;
447 
448 	case 'u':
449 	  type = CT_INT;
450 	  ccfn = _strtoul_r;
451 	  base = 10;
452 	  break;
453 
454 	case 'X':		/* compat   XXX */
455 	case 'x':
456 	  flags |= PFXOK;	/* enable 0x prefixing */
457 	  type = CT_INT;
458 	  ccfn = _strtoul_r;
459 	  base = 16;
460 	  break;
461 
462 #ifdef FLOATING_POINT
463 	case 'E':		/* compat   XXX */
464 	case 'G':		/* compat   XXX */
465 /* ANSI says that E,G and X behave the same way as e,g,x */
466 	  /* FALLTHROUGH */
467 	case 'e':
468 	case 'f':
469 	case 'g':
470 	  type = CT_FLOAT;
471 	  if (flags & VECTOR)
472 	    vec_read_count = 4;
473 	  break;
474 
475 # ifdef __SPE__
476 	  /* treat fixed-point like %f floating point */
477         case 'r':
478 	  flags |= SIGNED;
479 	  /* fallthrough */
480         case 'R':
481           flags |= FIXEDPOINT;
482 	  type = CT_FLOAT;
483           break;
484 # endif
485 #endif
486 
487 	case 's':
488 	  flags &= ~VECTOR;
489 	  type = CT_STRING;
490 	  break;
491 
492 	case '[':
493 	  fmt = __sccl (ccltab, fmt);
494 	  flags |= NOSKIP;
495 	  flags &= ~VECTOR;
496 	  type = CT_CCL;
497 	  break;
498 
499 	case 'c':
500 	  flags |= NOSKIP;
501 	  type = CT_CHAR;
502 	  if (flags & VECTOR)
503 	    {
504 	      /* not allowed to have h or l with c specifier */
505 	      if (flags & (LONG | SHORT))
506 		continue;  /* invalid format don't process any further */
507 	      width = 0;
508 	      vec_read_count = 16;
509 	    }
510 	  break;
511 
512 	case 'p':		/* pointer format is like hex */
513 	  flags |= POINTER | PFXOK;
514 	  type = CT_INT;
515 	  ccfn = _strtoul_r;
516 	  base = 16;
517 	  break;
518 
519 	case 'n':
520 	  if (flags & SUPPRESS)	/* ??? */
521 	    continue;
522 	  flags &= ~VECTOR;
523 	  if (flags & SHORT)
524 	    {
525 	      sp = va_arg (ap, short *);
526 	      *sp = nread;
527 	    }
528 	  else if (flags & LONG)
529 	    {
530 	      lp = va_arg (ap, long *);
531 	      *lp = nread;
532 	    }
533 #ifndef _NO_LONGLONG
534 	  else if (flags & LONGDBL)
535 	    {
536 	      llp = va_arg (ap, long long*);
537 	      *llp = nread;
538 	    }
539 #endif
540 	  else
541 	    {
542 	      ip = va_arg (ap, int *);
543 	      *ip = nread;
544 	    }
545 	  continue;
546 
547 	  /*
548 	   * Disgusting backwards compatibility hacks.	XXX
549 	   */
550 	case '\0':		/* compat */
551 	  return EOF;
552 
553 	default:		/* compat */
554 	  if (isupper (c))
555 	    flags |= LONG;
556 	  type = CT_INT;
557 	  ccfn = (u_long (*)())_strtol_r;
558 	  base = 10;
559 	  break;
560 	}
561 
562     process:
563       /*
564        * We have a conversion that requires input.
565        */
566       if (BufferEmpty)
567 	goto input_failure;
568 
569       /*
570        * Consume leading white space, except for formats that
571        * suppress this.
572        */
573       last_space_char = '\0';
574 
575       if ((flags & NOSKIP) == 0)
576 	{
577 	  while (isspace (*fp->_p))
578 	    {
579 	      last_space_char = *fp->_p;
580 	      nread++;
581 	      if (--fp->_r > 0)
582 		fp->_p++;
583 	      else
584 #ifndef CYGNUS_NEC
585 	      if (__srefill (fp))
586 #endif
587 		goto input_failure;
588 	    }
589 	  /*
590 	   * Note that there is at least one character in the
591 	   * buffer, so conversions that do not set NOSKIP ca
592 	   * no longer result in an input failure.
593 	   */
594 	}
595 
596       /* for vector formats process separator characters after first loop */
597       if (looped && (flags & VECTOR))
598 	{
599 	  flags = orig_flags;
600 	  /* all formats other than default char have a separator char */
601 	  if (vec_sep != ' ' || type != CT_CHAR)
602 	    {
603 	      if (vec_sep == ' ' && last_space_char != ' ' ||
604 		  vec_sep != ' ' && *fp->_p != vec_sep)
605 		goto match_failure;
606 	      if (vec_sep != ' ')
607 		{
608 		  nread++;
609 		  if (--fp->_r > 0)
610 		    fp->_p++;
611 		  else
612 #ifndef CYGNUS_NEC
613 		    if (__srefill (fp))
614 #endif
615 		      goto input_failure;
616 		}
617 	    }
618 	  /* after eating the separator char, we must eat any white-space
619 	     after the separator char that precedes the data to convert */
620 	  if ((flags & NOSKIP) == 0)
621 	    {
622 	      while (isspace (*fp->_p))
623 		{
624 		  last_space_char = *fp->_p;
625 		  nread++;
626 		  if (--fp->_r > 0)
627 		    fp->_p++;
628 		  else
629 #ifndef CYGNUS_NEC
630 		    if (__srefill (fp))
631 #endif
632 		      goto input_failure;
633 		}
634 	    }
635 
636  	}
637       else /* save to counter-act changes made to flags when processing */
638 	orig_flags = flags;
639 
640       /*
641        * Do the conversion.
642        */
643       switch (type)
644 	{
645 
646 	case CT_CHAR:
647 	  /* scan arbitrary characters (sets NOSKIP) */
648 	  if (width == 0)
649 	    width = 1;
650 	  if (flags & SUPPRESS)
651 	    {
652 	      size_t sum = 0;
653 
654 	      for (;;)
655 		{
656 		  if ((n = fp->_r) < (int)width)
657 		    {
658 		      sum += n;
659 		      width -= n;
660 		      fp->_p += n;
661 #ifndef CYGNUS_NEC
662 		      if (__srefill (fp))
663 			{
664 #endif
665 			  if (sum == 0)
666 			    goto input_failure;
667 			  break;
668 #ifndef CYGNUS_NEC
669 			}
670 #endif
671 		    }
672 		  else
673 		    {
674 		      sum += width;
675 		      fp->_r -= width;
676 		      fp->_p += width;
677 		      break;
678 		    }
679 		}
680 	      nread += sum;
681 	    }
682 	  else
683 	    {
684 	      int n = width;
685 	      if (!looped)
686 		{
687 		  if (flags & VECTOR)
688 		    ch_dest = vec_buf.c;
689 		  else
690 		    ch_dest = va_arg (ap, char *);
691 		}
692 #ifdef CYGNUS_NEC
693 	      /* Kludge city for the moment */
694 	      if (fp->_r == 0)
695 		goto input_failure;
696 
697 	      while (n && fp->_r)
698 		{
699 		  *ch_dest++ = *(fp->_p++);
700 		  n--;
701 		  fp->_r--;
702 		  nread++;
703 		}
704 #else
705 	      size_t r = fread (ch_dest, 1, width, fp);
706 
707 	      if (r == 0)
708 		goto input_failure;
709 	      nread += r;
710 	      ch_dest += r;
711 #endif
712 	      if (!(flags & VECTOR))
713 		nassigned++;
714 	    }
715 	  break;
716 
717 	case CT_CCL:
718 	  /* scan a (nonempty) character class (sets NOSKIP) */
719 	  if (width == 0)
720 	    width = ~0;		/* `infinity' */
721 	  /* take only those things in the class */
722 	  if (flags & SUPPRESS)
723 	    {
724 	      n = 0;
725 	      while (ccltab[*fp->_p])
726 		{
727 		  n++, fp->_r--, fp->_p++;
728 		  if (--width == 0)
729 		    break;
730 		  if (BufferEmpty)
731 		    {
732 		      if (n == 0)
733 			goto input_failure;
734 		      break;
735 		    }
736 		}
737 	      if (n == 0)
738 		goto match_failure;
739 	    }
740 	  else
741 	    {
742 	      p0 = p = va_arg (ap, char *);
743 	      while (ccltab[*fp->_p])
744 		{
745 		  fp->_r--;
746 		  *p++ = *fp->_p++;
747 		  if (--width == 0)
748 		    break;
749 		  if (BufferEmpty)
750 		    {
751 		      if (p == p0)
752 			goto input_failure;
753 		      break;
754 		    }
755 		}
756 	      n = p - p0;
757 	      if (n == 0)
758 		goto match_failure;
759 	      *p = 0;
760 	      nassigned++;
761 	    }
762 	  nread += n;
763 	  break;
764 
765 	case CT_STRING:
766 	  /* like CCL, but zero-length string OK, & no NOSKIP */
767 	  if (width == 0)
768 	    width = ~0;
769 	  if (flags & SUPPRESS)
770 	    {
771 	      n = 0;
772 	      while (!isspace (*fp->_p))
773 		{
774 		  n++, fp->_r--, fp->_p++;
775 		  if (--width == 0)
776 		    break;
777 		  if (BufferEmpty)
778 		    break;
779 		}
780 	      nread += n;
781 	    }
782 	  else
783 	    {
784 	      p0 = p = va_arg (ap, char *);
785 	      while (!isspace (*fp->_p))
786 		{
787 		  fp->_r--;
788 		  *p++ = *fp->_p++;
789 		  if (--width == 0)
790 		    break;
791 		  if (BufferEmpty)
792 		    break;
793 		}
794 	      *p = 0;
795 	      nread += p - p0;
796 	      nassigned++;
797 	    }
798 	  continue;
799 
800 	case CT_INT:
801 	  {
802 	  unsigned int_width_left = 0;
803 	  int skips = 0;
804 	  int_width = width;
805 #ifdef hardway
806 	  if (int_width == 0 || int_width > sizeof (buf) - 1)
807 #else
808 	  /* size_t is unsigned, hence this optimisation */
809 	  if (int_width - 1 > sizeof (buf) - 2)
810 #endif
811 	    {
812 	      int_width_left = width - (sizeof (buf) - 1);
813 	      int_width = sizeof (buf) - 1;
814 	    }
815 	  flags |= SIGNOK | NDIGITS | NZDIGITS | NNZDIGITS;
816 	  for (p = buf; int_width; int_width--)
817 	    {
818 	      c = *fp->_p;
819 	      /*
820 	       * Switch on the character; `goto ok' if we
821 	       * accept it as a part of number.
822 	       */
823 	      switch (c)
824 		{
825 		  /*
826 		   * The digit 0 is always legal, but is special.
827 		   * For %i conversions, if no digits (zero or nonzero)
828 		   * have been scanned (only signs), we will have base==0.
829 		   * In that case, we should set it to 8 and enable 0x
830 		   * prefixing. Also, if we have not scanned zero digits
831 		   * before this, do not turn off prefixing (someone else
832 		   * will turn it off if we have scanned any nonzero digits).
833 		   */
834 		case '0':
835 		  if (! (flags & NNZDIGITS))
836 		    goto ok;
837 		  if (base == 0)
838 		    {
839 		      base = 8;
840 		      flags |= PFXOK;
841 		    }
842 		  if (flags & NZDIGITS)
843 		    {
844 		      flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
845 		      goto ok;
846 		    }
847 		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
848 		  if (int_width_left)
849 		    {
850 		      int_width_left--;
851 		      int_width++;
852 		    }
853 		  ++skips;
854 		  goto skip;
855 
856 		  /* 1 through 7 always legal */
857 		case '1':
858 		case '2':
859 		case '3':
860 		case '4':
861 		case '5':
862 		case '6':
863 		case '7':
864 		  base = basefix[base];
865 		  flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
866 		  goto ok;
867 
868 		  /* digits 8 and 9 ok iff decimal or hex */
869 		case '8':
870 		case '9':
871 		  base = basefix[base];
872 		  if (base <= 8)
873 		    break;	/* not legal here */
874 		  flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
875 		  goto ok;
876 
877 		  /* letters ok iff hex */
878 		case 'A':
879 		case 'B':
880 		case 'C':
881 		case 'D':
882 		case 'E':
883 		case 'F':
884 		case 'a':
885 		case 'b':
886 		case 'c':
887 		case 'd':
888 		case 'e':
889 		case 'f':
890 		  /* no need to fix base here */
891 		  if (base <= 10)
892 		    break;	/* not legal here */
893 		  flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
894 		  goto ok;
895 
896 		  /* sign ok only as first character */
897 		case '+':
898 		case '-':
899 		  if (flags & SIGNOK)
900 		    {
901 		      flags &= ~SIGNOK;
902 		      goto ok;
903 		    }
904 		  break;
905 
906 		  /* x ok iff flag still set & 2nd char */
907 		case 'x':
908 		case 'X':
909 		  if (flags & PFXOK && p == buf + 1)
910 		    {
911 		      base = 16;/* if %i */
912 		      flags &= ~PFXOK;
913 		      /* We must reset the NZDIGITS and NDIGITS
914 		         flags that would have been unset by seeing
915 		         the zero that preceded the X or x.  */
916 		      flags |= NZDIGITS | NDIGITS;
917 		      goto ok;
918 		    }
919 		  break;
920 		}
921 
922 	      /*
923 	       * If we got here, c is not a legal character
924 	       * for a number.  Stop accumulating digits.
925 	       */
926 	      break;
927 	    ok:
928 	      /*
929 	       * c is legal: store it and look at the next.
930 	       */
931 	      *p++ = c;
932 	    skip:
933 	      if (--fp->_r > 0)
934 		fp->_p++;
935 	      else
936 #ifndef CYGNUS_NEC
937 	      if (__srefill (fp))
938 #endif
939 		break;		/* EOF */
940 	    }
941 	  /*
942 	   * If we had only a sign, it is no good; push back the sign.
943 	   * If the number ends in `x', it was [sign] '0' 'x', so push back
944 	   * the x and treat it as [sign] '0'.
945 	   */
946 	  if (flags & NDIGITS)
947 	    {
948 	      if (p > buf)
949 		_CAST_VOID ungetc (*(u_char *)-- p, fp);
950 	      goto match_failure;
951 	    }
952 	  c = ((u_char *) p)[-1];
953 	  if (c == 'x' || c == 'X')
954 	    {
955 	      --p;
956 	      /*(void)*/ ungetc (c, fp);
957 	    }
958 	  if ((flags & SUPPRESS) == 0)
959 	    {
960 	      u_long res;
961 
962 	      *p = 0;
963 	      res = (*ccfn) (rptr, buf, (char **) NULL, base);
964 	      if ((flags & POINTER) && !(flags & VECTOR))
965 		*(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
966 	      else if (flags & SHORT)
967 		{
968 		  if (!(flags & VECTOR))
969 		    sp = va_arg (ap, short *);
970 		  else if (!looped)
971 		    sp = vec_buf.h;
972 		  *sp++ = res;
973 		}
974 	      else if (flags & LONG)
975 		{
976 		  if (!(flags & VECTOR))
977 		    lp = va_arg (ap, long *);
978 		  else if (!looped)
979 		    lp = vec_buf.l;
980 		  *lp++ = res;
981 		}
982 #ifndef _NO_LONGLONG
983 	      else if (flags & LONGDBL)
984 		{
985 		  u_long_long resll;
986 		  if (ccfn == _strtoul_r)
987 		    resll = _strtoull_r (rptr, buf, (char **) NULL, base);
988 		  else
989 		    resll = _strtoll_r (rptr, buf, (char **) NULL, base);
990 		  llp = va_arg (ap, long long*);
991 		  *llp = resll;
992 		}
993 #endif
994 	      else
995 		{
996 		  if (!(flags & VECTOR))
997 		    {
998 		      ip = va_arg (ap, int *);
999 		      *ip++ = res;
1000 		    }
1001 		  else
1002 		    {
1003 		      if (!looped)
1004 			ch_dest = vec_buf.c;
1005 		      *ch_dest++ = (char)res;
1006 		    }
1007 		}
1008 	      if (!(flags & VECTOR))
1009 		nassigned++;
1010 	    }
1011 	  nread += p - buf + skips;
1012 	  break;
1013 	  }
1014 
1015 #ifdef FLOATING_POINT
1016 	case CT_FLOAT:
1017 	{
1018 	  /* scan a floating point number as if by strtod */
1019 	  /* This code used to assume that the number of digits is reasonable.
1020 	     However, ANSI / ISO C makes no such stipulation; we have to get
1021 	     exact results even when there is an unreasonable amount of
1022 	     leading zeroes.  */
1023 	  long leading_zeroes = 0;
1024 	  long zeroes, exp_adjust;
1025 	  char *exp_start = NULL;
1026 	  unsigned fl_width = width;
1027 	  unsigned width_left = 0;
1028 #ifdef hardway
1029 	  if (fl_width == 0 || fl_width > sizeof (buf) - 1)
1030 #else
1031 	  /* size_t is unsigned, hence this optimisation */
1032 	  if (fl_width - 1 > sizeof (buf) - 2)
1033 #endif
1034 	    {
1035 	      width_left = fl_width - (sizeof (buf) - 1);
1036 	      fl_width = sizeof (buf) - 1;
1037 	    }
1038 	  flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1039 	  zeroes = 0;
1040 	  exp_adjust = 0;
1041 	  for (p = buf; fl_width; )
1042 	    {
1043 	      c = *fp->_p;
1044 	      /*
1045 	       * This code mimicks the integer conversion
1046 	       * code, but is much simpler.
1047 	       */
1048 	      switch (c)
1049 		{
1050 
1051 		case '0':
1052 		  if (flags & NDIGITS)
1053 		    {
1054 		      flags &= ~SIGNOK;
1055 		      zeroes++;
1056 		      if (width_left)
1057 			{
1058 			  width_left--;
1059 			  fl_width++;
1060 			}
1061 		      goto fskip;
1062 		    }
1063 		  /* Fall through.  */
1064 		case '1':
1065 		case '2':
1066 		case '3':
1067 		case '4':
1068 		case '5':
1069 		case '6':
1070 		case '7':
1071 		case '8':
1072 		case '9':
1073 		  flags &= ~(SIGNOK | NDIGITS);
1074 		  goto fok;
1075 
1076 		case '+':
1077 		case '-':
1078 		  if (flags & SIGNOK)
1079 		    {
1080 		      flags &= ~SIGNOK;
1081 		      goto fok;
1082 		    }
1083 		  break;
1084 		case '.':
1085 		  if (flags & DPTOK)
1086 		    {
1087 		      flags &= ~(SIGNOK | DPTOK);
1088 		      leading_zeroes = zeroes;
1089 		      goto fok;
1090 		    }
1091 		  break;
1092 		case 'e':
1093 		case 'E':
1094 		  /* no exponent without some digits */
1095 		  if ((flags & (NDIGITS | EXPOK)) == EXPOK
1096 		      || ((flags & EXPOK) && zeroes))
1097 		    {
1098 		      if (! (flags & DPTOK))
1099 			{
1100 			  exp_adjust = zeroes - leading_zeroes;
1101 			  exp_start = p;
1102 			}
1103 		      flags =
1104 			(flags & ~(EXPOK | DPTOK)) |
1105 			SIGNOK | NDIGITS;
1106 		      zeroes = 0;
1107 		      goto fok;
1108 		    }
1109 		  break;
1110 		}
1111 	      break;
1112 	    fok:
1113 	      *p++ = c;
1114 	    fskip:
1115 	      fl_width--;
1116               ++nread;
1117 	      if (--fp->_r > 0)
1118 		fp->_p++;
1119 	      else
1120 #ifndef CYGNUS_NEC
1121 	      if (__srefill (fp))
1122 #endif
1123 		break;		/* EOF */
1124 	    }
1125 	  if (zeroes)
1126 	    flags &= ~NDIGITS;
1127 	  /*
1128 	   * If no digits, might be missing exponent digits
1129 	   * (just give back the exponent) or might be missing
1130 	   * regular digits, but had sign and/or decimal point.
1131 	   */
1132 	  if (flags & NDIGITS)
1133 	    {
1134 	      if (flags & EXPOK)
1135 		{
1136 		  /* no digits at all */
1137 		  while (p > buf)
1138                     {
1139 		      ungetc (*(u_char *)-- p, fp);
1140                       --nread;
1141                     }
1142 		  goto match_failure;
1143 		}
1144 	      /* just a bad exponent (e and maybe sign) */
1145 	      c = *(u_char *)-- p;
1146               --nread;
1147 	      if (c != 'e' && c != 'E')
1148 		{
1149 		  _CAST_VOID ungetc (c, fp);	/* sign */
1150 		  c = *(u_char *)-- p;
1151                   --nread;
1152 		}
1153 	      _CAST_VOID ungetc (c, fp);
1154 	    }
1155 	  if ((flags & SUPPRESS) == 0)
1156 	    {
1157 #ifdef _NO_LONGDBL
1158 	      double res;
1159 #else  /* !_NO_LONG_DBL */
1160 	      long double res;
1161 #endif /* !_NO_LONG_DBL */
1162 	      long new_exp = 0;
1163 
1164 	      *p = 0;
1165 	      if ((flags & (DPTOK | EXPOK)) == EXPOK)
1166 		{
1167 		  exp_adjust = zeroes - leading_zeroes;
1168 		  new_exp = -exp_adjust;
1169 		  exp_start = p;
1170 		}
1171 	      else if (exp_adjust)
1172                 new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1173 	      if (exp_adjust)
1174 		{
1175 
1176 		  /* If there might not be enough space for the new exponent,
1177 		     truncate some trailing digits to make room.  */
1178 		  if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
1179 		    exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
1180                  sprintf (exp_start, "e%ld", new_exp);
1181 		}
1182 #ifdef __SPE__
1183 	      if (flags & FIXEDPOINT)
1184 		{
1185 		  __uint64_t ufix64;
1186 		  if (flags & SIGNED)
1187 		    ufix64 = (__uint64_t)_strtosfix64_r (rptr, buf, NULL);
1188                   else
1189 		    ufix64 = _strtoufix64_r (rptr, buf, NULL);
1190 		  if (flags & SHORT)
1191 		    {
1192 		      __uint16_t *sp = va_arg (ap, __uint16_t *);
1193 		      *sp = (__uint16_t)(ufix64 >> 48);
1194 		    }
1195 		  else if (flags & LONG)
1196 		    {
1197 		      __uint64_t *llp = va_arg (ap, __uint64_t *);
1198 		      *llp = ufix64;
1199 		    }
1200 		  else
1201 		    {
1202 		      __uint32_t *lp = va_arg (ap, __uint32_t *);
1203 		      *lp = (__uint32_t)(ufix64 >> 32);
1204 		    }
1205 		  nassigned++;
1206 		  break;
1207 		}
1208 
1209 #endif /* __SPE__ */
1210 #ifdef _NO_LONGDBL
1211 	      res = _strtod_r (rptr, buf, NULL);
1212 #else  /* !_NO_LONGDBL */
1213 	      res = _strtold_r (rptr, buf, NULL);
1214 #endif /* !_NO_LONGDBL */
1215 	      if (flags & LONG)
1216 		{
1217 		  dp = va_arg (ap, double *);
1218 		  *dp = res;
1219 		}
1220 	      else if (flags & LONGDBL)
1221 		{
1222 		  ldp = va_arg (ap, _LONG_DOUBLE *);
1223 		  *ldp = res;
1224 		}
1225 	      else
1226 		{
1227 		  if (!(flags & VECTOR))
1228 		    flp = va_arg (ap, float *);
1229 		  else if (!looped)
1230 		    flp = vec_buf.f;
1231 		  *flp++ = res;
1232 		}
1233 	      if (!(flags & VECTOR))
1234 		nassigned++;
1235 	    }
1236 	  break;
1237 	}
1238 #endif /* FLOATING_POINT */
1239 	}
1240       if (vec_read_count-- > 1)
1241 	{
1242 	  looped = 1;
1243 	  goto process;
1244 	}
1245       if (flags & VECTOR)
1246 	{
1247 	  int i;
1248 	  unsigned long *vp = va_arg (ap, unsigned long *);
1249 	  for (i = 0; i < 4; ++i)
1250 	    *vp++ = vec_buf.l[i];
1251 	  nassigned++;
1252 	}
1253     }
1254 input_failure:
1255   return nassigned ? nassigned : -1;
1256 match_failure:
1257   return nassigned;
1258 }
1259 
1260