Contiki 2.5
small_vfsscanf.c
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 *<[fmt]>, va_list <[list]>);
16  int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
17  int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
18 
19  int _vscanf_r(void *<[reent]>, const char *<[fmt]>,
20  va_list <[list]>);
21  int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
22  va_list <[list]>);
23  int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[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 
106 
107 #include <_ansi.h>
108 //#include <ctype.h>
109 #include <wctype.h>
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <limits.h>
113 #include <wchar.h>
114 #include <string.h>
115 
116 
117 #ifdef _HAVE_STDC
118 #include <stdarg.h>
119 #else
120 #include <varargs.h>
121 #endif
122 
123 #ifndef SMALL_SCANF
124 #include "local.h"
125 #endif
126 
127 
128 #ifndef NO_FLOATING_POINT
129 #include <float.h>
130 #endif
131 
132 
133 
134 #ifndef NO_FLOATING_POINT
135 #define FLOATING_POINT
136 #endif
137 
138 #ifdef FLOATING_POINT
139 #include <float.h>
140 
141 /* Currently a test is made to see if long double processing is warranted.
142  This could be changed in the future should the _ldtoa_r code be
143  preferred over _dtoa_r. */
144 #define _NO_LONGDBL
145 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
146 #undef _NO_LONGDBL
147 extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
148 #endif
149 
150 #define _NO_LONGLONG
151 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
152 # undef _NO_LONGLONG
153 #endif
154 
155 #include "floatio.h"
156 
157 #if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
158 # define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
159 #else
160 # define BUF MB_LEN_MAX
161 #endif
162 
163 /* An upper bound for how long a long prints in decimal. 4 / 13 approximates
164  log (2). Add one char for roundoff compensation and one for the sign. */
165 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2)
166 #else
167 #define BUF 40
168 #endif
169 
170 
171 /*
172  * Flags used during conversion.
173  */
174 
175 #define LONG 0x01 /* l: long or double */
176 #define LONGDBL 0x02 /* L/ll: long double or long long */
177 #define SHORT 0x04 /* h: short */
178 #define CHAR 0x08 /* hh: 8 bit integer */
179 #define SUPPRESS 0x10 /* suppress assignment */
180 #define POINTER 0x20 /* weird %p pointer (`fake hex') */
181 #define NOSKIP 0x40 /* do not skip blanks */
182 
183 /*
184  * The following are used in numeric conversions only:
185  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
186  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
187  */
188 
189 #define SIGNOK 0x80 /* +/- is (still) legal */
190 #define NDIGITS 0x100 /* no digits detected */
191 
192 #define DPTOK 0x200 /* (float) decimal point is still legal */
193 #define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
194 
195 #define PFXOK 0x200 /* 0x prefix is (still) legal */
196 #define NZDIGITS 0x400 /* no zero digits detected */
197 
198 /*
199  * Conversion types.
200  */
201 
202 #define CT_CHAR 0 /* %c conversion */
203 #define CT_CCL 1 /* %[...] conversion */
204 #define CT_STRING 2 /* %s conversion */
205 #define CT_INT 3 /* integer, i.e., strtol or strtoul */
206 #define CT_FLOAT 4 /* floating, i.e., strtod */
207 
208 #if 0
209 #define u_char unsigned char
210 #endif
211 #define u_char char
212 #define u_long unsigned long
213 
214 #ifndef _NO_LONGLONG
215 typedef unsigned long long u_long_long;
216 #endif
217 
218 /*static*/ u_char *__sccl ();
219 
220 /*
221  * vfscanf
222  */
223 
224 #ifndef SMALL_SCANF
225 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
226 
227 #else // SMALL_SCANF
228 
229 unsigned char buf_ungetc ;
230 int flag_buf_ungetc = 0 ;
231 #define buf_ungetc_empty 0
232 #define buf_ungetc_full 1
233 
234 
235 /*
236  Redefinition of ungetc : store in a buffer a character
237  Only ONE ungetc is allowed before a getchar
238  For each getchar, new_getchar() is called, then the buf is tested:
239  - if flag_buf_ungetc == 0 : new_getchar call __io_getchar()
240  - if flag_buf_ungetc == 1 : new_getchar returns character in the buffer
241 
242  */
243 
244 
245 
246 
247 int __io_ungetc(int c){
248 
249 if (flag_buf_ungetc == 0){
250  flag_buf_ungetc = buf_ungetc_full; //flag to 1 to indicate that a caracter is in the buffer
251 }
252 buf_ungetc= (unsigned char)c ;
253 
254 return (c);
255 }
256 
257 int new_getchar() {
258 if (flag_buf_ungetc == 0){
259 
260  return __io_getchar();
261 
262 }
263 else {
264 
265  flag_buf_ungetc = buf_ungetc_empty;
266  return buf_ungetc;
267 
268 }
269 
270 }
271 
272 #endif // SMALL_SCANF
273 
274 #ifndef _REENT_ONLY
275 
276 int
277 _DEFUN (vfscanf, (fp, fmt, ap),
278  register FILE *fp _AND
279  _CONST char *fmt _AND
280  va_list ap)
281 {
282 
283  #ifndef SMALL_SCANF
284  CHECK_INIT(fp);
285  #endif
286 
287  return __svfscanf_r (_REENT, fp, fmt, ap);
288 }
289 
290 int
291 __svfscanf (fp, fmt0, ap)
292  register FILE *fp;
293  char _CONST *fmt0;
294  va_list ap;
295 {
296  return __svfscanf_r (_REENT, fp, fmt0, ap);
297 }
298 
299 #endif /* !_REENT_ONLY */
300 
301 int
302 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
303  struct _reent *data _AND
304  register FILE *fp _AND
305  _CONST char *fmt _AND
306  va_list ap)
307 {
308  return __svfscanf_r (data, fp, fmt, ap);
309 }
310 
311 
312 
313 /*
314 
315 
316 For SMALL_SCANF :
317 The use of files has been removed so as to use directly __io_getchar()
318 Buffer_empty is not anymore tested since _io_getchar() is blocked until
319 a character is entered.
320 Generally each *fp->_p ++ which equal to read a character on the file
321 has been replaced by a new_getchar() which call __io_getchar();
322 
323 
324 */
325 
326 int
327 __svfscanf_r (rptr, fp, fmt0, ap)
328  struct _reent *rptr;
329  register FILE *fp;
330  char _CONST *fmt0;
331  va_list ap;
332 {
333 
334  register char * bufread;
335  register u_char *fmt = (u_char *) fmt0;
336  register int c; /* character from format, or conversion */
337  register int car;
338  register size_t width; /* field width, or 0 */
339  register char *p; /* points into all kinds of strings */
340  register int n; /* handy integer */
341  register int flags; /* flags as defined above */
342  register char *p0; /* saves original value of p when necessary */
343  int nassigned; /* number of fields assigned */
344  int nread; /* number of characters consumed from fp */
345  int base = 0; /* base argument to strtol/strtoul */
346  int nbytes = 1; /* number of bytes read from fmt string */
347  wchar_t wc; /* wchar to use to read format string */
348  wchar_t *wcp; /* handy wide character pointer */
349  size_t mbslen; /* length of converted multibyte sequence */
350  mbstate_t state; /* value to keep track of multibyte state */
351 
352  u_long (*ccfn) () = 0; /* conversion function (strtol/strtoul) */
353  char ccltab[256]; /* character class table for %[...] */
354  char buf[BUF]; /* buffer for numeric conversions */
355  char *lptr; /* literal pointer */
356 
357  char *cp;
358  short *sp;
359  int *ip;
360  float *flp;
361  _LONG_DOUBLE *ldp;
362  double *dp;
363  long *lp;
364 #ifndef _NO_LONGLONG
365  long long *llp;
366 #endif
367 
368  /* `basefix' is used to avoid `if' tests in the integer scanner */
369  static _CONST short basefix[17] =
370  {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
371 
372  nassigned = 0;
373  nread = 0;
374  for (;;)
375  {
376 #ifndef MB_CAPABLE
377  wc = *fmt;
378 #else
379  memset (&state, '\0', sizeof (state));
380  nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
381 #endif
382  fmt += nbytes;
383  if (wc == 0)
384  return nassigned;
385  if (nbytes == 1 && isspace (wc))
386  {
387  for (;;)
388  {
389  #ifndef SMALL_SCANF
390  if (BufferEmpty || !isspace (*fp->_p))
391  break;
392  nread++, fp->_r--, fp->_p++;
393 
394  #else
395  if (!isspace (*fp->_p)) break;
396  nread++, fp->_r--;
397  *fp->_p = new_getchar();
398 
399  #endif
400  }
401 
402  continue;
403  }
404  if (wc != '%')
405  goto literal;
406  width = 0;
407  flags = 0;
408 
409  /*
410  * switch on the format. continue if done; break once format
411  * type is derived.
412  */
413 
414  again:
415  c = *fmt++;
416  switch (c)
417  {
418  case '%':
419  literal:
420  lptr = fmt - nbytes;
421  for (n = 0; n < nbytes; ++n)
422  {
423  #ifndef SMALL_SCANF
424  if (BufferEmpty)
425  goto input_failure;
426  #else
427  *fp->_p = new_getchar();
428  #endif
429 
430  if (*fp->_p != *lptr)
431  goto match_failure;
432  #ifndef SMALL_SCANF
433  fp->_r--, fp->_p++;
434  nread++;
435  #else
436  fp->_r--;
437  *fp->_p = new_getchar();
438  nread++;
439  #endif
440  ++lptr;
441  }
442  continue;
443 
444  case '*':
445  flags |= SUPPRESS;
446  goto again;
447  case 'l':
448  if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */
449  {
450  ++fmt;
451  flags |= LONGDBL;
452  }
453  else
454  flags |= LONG;
455  goto again;
456  case 'L':
457  flags |= LONGDBL;
458  goto again;
459  case 'h':
460  if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
461  {
462  ++fmt;
463  flags |= CHAR;
464  }
465  else
466  flags |= SHORT;
467  goto again;
468 
469  case '0':
470  case '1':
471  case '2':
472  case '3':
473  case '4':
474  case '5':
475  case '6':
476  case '7':
477  case '8':
478  case '9':
479  width = width * 10 + c - '0';
480  goto again;
481 
482  /*
483  * Conversions. Those marked `compat' are for
484  * 4.[123]BSD compatibility.
485  *
486  * (According to ANSI, E and X formats are supposed to
487  * the same as e and x. Sorry about that.)
488  */
489 
490  case 'D': /* compat */
491  flags |= LONG;
492  /* FALLTHROUGH */
493  case 'd':
494  c = CT_INT;
495  ccfn = (u_long (*)())_strtol_r;
496  base = 10;
497  break;
498 
499  case 'i':
500  c = CT_INT;
501  ccfn = (u_long (*)())_strtol_r;
502  base = 0;
503  break;
504 
505  case 'O': /* compat */
506  flags |= LONG;
507  /* FALLTHROUGH */
508  case 'o':
509  c = CT_INT;
510  ccfn = _strtoul_r;
511  base = 8;
512  break;
513 
514  case 'u':
515  c = CT_INT;
516  ccfn = _strtoul_r;
517  base = 10;
518  break;
519 
520  case 'X': /* compat XXX */
521  case 'x':
522  flags |= PFXOK; /* enable 0x prefixing */
523  c = CT_INT;
524  ccfn = _strtoul_r;
525  base = 16;
526  break;
527 
528 #ifdef FLOATING_POINT
529  case 'E': /* compat XXX */
530  case 'G': /* compat XXX */
531 /* ANSI says that E,G and X behave the same way as e,g,x */
532  /* FALLTHROUGH */
533  case 'e':
534  case 'f':
535  case 'g':
536  c = CT_FLOAT;
537  break;
538 #endif
539  case 'S':
540  flags |= LONG;
541  /* FALLTHROUGH */
542 
543  case 's':
544  c = CT_STRING;
545  break;
546 
547  case '[':
548  fmt = __sccl (ccltab, fmt);
549  flags |= NOSKIP;
550  c = CT_CCL;
551  break;
552 
553  case 'C':
554  flags |= LONG;
555  /* FALLTHROUGH */
556 
557  case 'c':
558  flags |= NOSKIP;
559  c = CT_CHAR;
560  break;
561 
562  case 'p': /* pointer format is like hex */
563  flags |= POINTER | PFXOK;
564  c = CT_INT;
565  ccfn = _strtoul_r;
566  base = 16;
567  break;
568 
569  case 'n':
570  if (flags & SUPPRESS) /* ??? */
571  continue;
572  if (flags & CHAR)
573  {
574  cp = va_arg (ap, char *);
575  *cp = nread;
576  }
577  else if (flags & SHORT)
578  {
579  sp = va_arg (ap, short *);
580  *sp = nread;
581  }
582  else if (flags & LONG)
583  {
584  lp = va_arg (ap, long *);
585  *lp = nread;
586  }
587 #ifndef _NO_LONGLONG
588  else if (flags & LONGDBL)
589  {
590  llp = va_arg (ap, long long*);
591  *llp = nread;
592  }
593 #endif
594  else
595  {
596  ip = va_arg (ap, int *);
597  *ip = nread;
598  }
599  continue;
600 
601  /*
602  * Disgusting backwards compatibility hacks. XXX
603  */
604  case '\0': /* compat */
605  return EOF;
606 
607  default: /* compat */
608  if (isupper (c))
609  flags |= LONG;
610  c = CT_INT;
611  ccfn = (u_long (*)())_strtol_r;
612  base = 10;
613  break;
614  }
615 
616  /*
617  * We have a conversion that requires input.
618  */
619  #ifndef SMALL_SCANF
620  if (BufferEmpty)
621  goto input_failure;
622  #else
623  *fp->_p = new_getchar();
624  #endif
625 
626  /*
627  * Consume leading white space, except for formats that
628  * suppress this.
629  */
630 
631  if ((flags & NOSKIP) == 0)
632  {
633  while (isspace (*fp->_p))
634  {
635  #ifndef SMALL_SCANF
636  nread++;
637  if (--fp->_r > 0)
638  fp->_p++;
639  else
640  if (__srefill (fp))
641  goto input_failure;
642  #else
643  *fp->_p = new_getchar();
644  #endif
645  }
646  /*
647  * Note that there is at least one character in the
648  * buffer, so conversions that do not set NOSKIP ca
649  * no longer result in an input failure.
650  */
651  }
652 
653  /*
654  * Do the conversion.
655  */
656  switch (c)
657  {
658 
659  case CT_CHAR:
660  /* scan arbitrary characters (sets NOSKIP) */
661  if (width == 0)
662  width = 1;
663  if (flags & LONG)
664  {
665  if ((flags & SUPPRESS) == 0)
666  wcp = va_arg(ap, wchar_t *);
667  else
668  wcp = NULL;
669  n = 0;
670  while (width != 0)
671  {
672 
673  if (n == MB_CUR_MAX)
674  goto input_failure;
675  #ifndef SMALL_SCANF
676  buf[n++] = *fp->_p;
677  fp->_r -= 1;
678  fp->_p += 1;
679  memset((void *)&state, '\0', sizeof(mbstate_t));
680  if ((mbslen = _mbrtowc_r(rptr, wcp, buf, n, &state))
681  == (size_t)-1)
682  goto input_failure; /* Invalid sequence */
683  #else
684  buf[n++] = *fp->_p;
685  *fp->_p = new_getchar();
686 
687  #endif
688 
689  if (mbslen == 0 && !(flags & SUPPRESS))
690  *wcp = L'\0';
691  if (mbslen != (size_t)-2) /* Incomplete sequence */
692  {
693  nread += n;
694  width -= 1;
695  if (!(flags & SUPPRESS))
696  wcp += 1;
697  n = 0;
698  }
699  #ifndef SMALL_SCANF
700  if (BufferEmpty)
701  {
702  if (n != 0)
703  goto input_failure;
704  break;
705  }
706  #endif
707  }
708  if (!(flags & SUPPRESS))
709  nassigned++;
710  }
711  else if (flags & SUPPRESS)
712  {
713  size_t sum = 0;
714  for (;;)
715  {
716  if ((n = fp->_r) < (int)width)
717  {
718  sum += n;
719  width -= n;
720  #ifndef SMALL_SCANF
721  fp->_p += n;
722  if (__srefill (fp))
723  {
724  if (sum == 0)
725  goto input_failure;
726  break;
727  }
728  #else
729  *fp->_p = new_getchar();
730  #endif
731 
732  }
733  else
734  {
735  sum += width;
736  fp->_r -= width;
737  #ifndef SMALL_SCANF
738  fp->_p += width;
739  #else
740  *fp->_p = new_getchar();
741  #endif
742 
743  break;
744  }
745  }
746  nread += sum;
747  }
748  else
749  {
750 
751  #ifndef SMALL_SCANF
752  size_t r = fread ((_PTR) va_arg (ap, char *), 1, width, fp);
753  if (r == 0)
754  goto input_failure;
755  nread += r;
756  nassigned++;
757 
758  #else
759  bufread=(_PTR)va_arg(ap,char *);
760  int r;
761  for (r=0;r<width;r++){
762  *bufread++= *fp->_p;
763  if ( r+1 < width){
764  *fp->_p = new_getchar();
765  }
766  }
767  #endif
768  }
769  break;
770 
771  case CT_CCL:
772  /* scan a (nonempty) character class (sets NOSKIP) */
773  if (width == 0)
774  width = ~0; /* `infinity' */
775  /* take only those things in the class */
776  if (flags & SUPPRESS)
777  {
778  n = 0;
779  while (ccltab[*fp->_p])
780  {
781  #ifndef SMALL_SCANF
782  n++, fp->_r--, fp->_p++;
783  if (--width == 0)
784  break;
785  if (BufferEmpty)
786  {
787  if (n == 0)
788  goto input_failure;
789  break;
790  }
791  #else
792  n++;
793  fp->_r++;
794  *fp->_p = new_getchar();
795  #endif
796 
797  }
798  if (n == 0)
799  goto match_failure;
800  }
801  else
802  {
803  p0 = p = va_arg (ap, char *);
804  while (ccltab[*fp->_p])
805  {
806  fp->_r--;
807  #ifndef SMALL_SCANF
808  *p++ = *fp->_p++;
809  if (--width == 0)
810  break;
811  if (BufferEmpty)
812  {
813  if (p == p0)
814  goto input_failure;
815  break;
816  }
817  #else
818  *p++ = *fp->_p;
819  *fp->_p= new_getchar();
820  if (--width == 0)
821  break;
822  #endif
823 
824  }
825  n = p - p0;
826  if (n == 0)
827  goto match_failure;
828  *p = 0;
829  nassigned++;
830  }
831  nread += n;
832  break;
833 
834  case CT_STRING:
835  /* like CCL, but zero-length string OK, & no NOSKIP */
836 
837  if (width == 0)
838  width = (size_t)~0;
839  if (flags & LONG)
840  {
841  /* Process %S and %ls placeholders */
842  if ((flags & SUPPRESS) == 0)
843  wcp = va_arg(ap, wchar_t *);
844  else
845  wcp = &wc;
846  n = 0;
847  while (!isspace(*fp->_p) && width != 0)
848  {
849  if (n == MB_CUR_MAX)
850  goto input_failure;
851  buf[n++] = *fp->_p;
852  fp->_r -= 1;
853  #ifndef SMALL_SCANF
854  fp->_p += 1;
855  memset((void *)&state, '\0', sizeof(mbstate_t));
856  if ((mbslen = _mbrtowc_r(rptr, wcp, buf, n, &state))
857  == (size_t)-1)
858  goto input_failure;
859  #else
860  *fp->_p = new_getchar();
861  #endif
862 
863  if (mbslen == 0)
864  *wcp = L'\0';
865 
866  if (mbslen != (size_t)-2) /* Incomplete sequence */
867  {
868  if (iswspace(*wcp))
869  {
870 
871  while (n != 0)
872  #ifndef SMALL_SCANF
873  ungetc(buf[--n], fp);
874  #else
875  __io_ungetc(buf[--n]);
876  #endif
877  break;
878 
879  }
880 
881  nread += n;
882  width -= 1;
883  if ((flags & SUPPRESS) == 0)
884  wcp += 1;
885  n = 0;
886  }
887  #ifndef SMALL_SCANF
888  if (BufferEmpty)
889  {
890  if (n != 0)
891  goto input_failure;
892  break;
893  }
894  #endif
895 
896  }
897  if (!(flags & SUPPRESS))
898  {
899  *wcp = L'\0';
900  nassigned++;
901  }
902  }
903  else if (flags & SUPPRESS)
904  {
905  n = 0;
906  while (!isspace (*fp->_p))
907  {
908  #ifndef SMALL_SCANF
909  n++, fp->_r--, fp->_p++;
910  if (--width == 0)
911  break;
912  if (BufferEmpty)
913  break;
914  #else
915  n++;
916  *fp->_p = new_getchar();
917  if (*fp->_p == '\0') break;
918  #endif
919 
920  }
921  nread += n;
922  }
923  else
924  {
925  p0 = p = va_arg (ap, char *);
926  while (!isspace (*fp->_p))
927  {
928  #ifndef SMALL_SCANF
929  fp->_r--;
930  *p++ = *fp->_p++;
931  if (--width == 0)
932  break;
933  if (BufferEmpty)
934  break;
935  #else
936  *p++=*fp->_p;
937  *fp->_p = new_getchar();
938  if (*fp->_p == '\0') break;
939  #endif
940 
941 
942  }
943  *p = 0;
944  nread += p - p0;
945  nassigned++;
946  }
947  continue;
948 
949  case CT_INT:
950  /* scan an integer as if by strtol/strtoul */
951 #ifdef hardway
952  if (width == 0 || width > sizeof (buf) - 1)
953  width = sizeof (buf) - 1;
954 #else
955  /* size_t is unsigned, hence this optimisation */
956  if (--width > sizeof (buf) - 2)
957  width = sizeof (buf) - 2;
958  width++;
959 #endif
960  flags |= SIGNOK | NDIGITS | NZDIGITS;
961  for (p = buf; width; width--)
962  {
963  c = *fp->_p;
964  /*
965  * Switch on the character; `goto ok' if we
966  * accept it as a part of number.
967  */
968  switch (c)
969  {
970  /*
971  * The digit 0 is always legal, but is special.
972  * For %i conversions, if no digits (zero or nonzero)
973  * have been scanned (only signs), we will have base==0.
974  * In that case, we should set it to 8 and enable 0x
975  * prefixing. Also, if we have not scanned zero digits
976  * before this, do not turn off prefixing (someone else
977  * will turn it off if we have scanned any nonzero digits).
978  */
979  case '0':
980  if (base == 0)
981  {
982  base = 8;
983  flags |= PFXOK;
984  }
985  if (flags & NZDIGITS)
986  flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
987  else
988  flags &= ~(SIGNOK | PFXOK | NDIGITS);
989  goto ok;
990 
991  /* 1 through 7 always legal */
992  case '1':
993  case '2':
994  case '3':
995  case '4':
996  case '5':
997  case '6':
998  case '7':
999  base = basefix[base];
1000  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1001  goto ok;
1002 
1003  /* digits 8 and 9 ok iff decimal or hex */
1004  case '8':
1005  case '9':
1006  base = basefix[base];
1007  if (base <= 8)
1008  break; /* not legal here */
1009  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1010  goto ok;
1011 
1012  /* letters ok iff hex */
1013  case 'A':
1014  case 'B':
1015  case 'C':
1016  case 'D':
1017  case 'E':
1018  case 'F':
1019  case 'a':
1020  case 'b':
1021  case 'c':
1022  case 'd':
1023  case 'e':
1024  case 'f':
1025  /* no need to fix base here */
1026  if (base <= 10)
1027  break; /* not legal here */
1028  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1029  goto ok;
1030 
1031  /* sign ok only as first character */
1032  case '+':
1033  case '-':
1034  if (flags & SIGNOK)
1035  {
1036  flags &= ~SIGNOK;
1037  goto ok;
1038  }
1039  break;
1040 
1041  /* x ok iff flag still set & 2nd char */
1042  case 'x':
1043  case 'X':
1044  if (flags & PFXOK && p == buf + 1)
1045  {
1046  base = 16;/* if %i */
1047  flags &= ~PFXOK;
1048  goto ok;
1049  }
1050  break;
1051  }
1052  /*
1053  * If we got here, c is not a legal character
1054  * for a number. Stop accumulating digits.
1055  */
1056 
1057  break;
1058  ok:
1059  /*
1060  * c is legal: store it and look at the next.
1061  */
1062  *p++ = c;
1063  #ifndef SMALL_SCANF
1064  if (--fp->_r > 0)
1065  fp->_p++;
1066  else
1067  if (__srefill (fp))
1068  break; /* EOF */
1069  #else
1070 
1071  *fp->_p = new_getchar();
1072 
1073  #endif
1074 
1075  }
1076  /*
1077  * If we had only a sign, it is no good; push back the sign.
1078  * If the number ends in `x', it was [sign] '0' 'x', so push back
1079  * the x and treat it as [sign] '0'.
1080  */
1081 
1082  if (flags & NDIGITS)
1083  {
1084  if (p > buf)
1085  #ifndef SMALL_SCANF
1086  _CAST_VOID ungetc (*(u_char *)-- p, fp);
1087  #else
1088  _CAST_VOID __io_ungetc (*(u_char *)-- p);
1089  #endif
1090  goto match_failure;
1091 
1092  }
1093 
1094  c = ((u_char *) p)[-1];
1095  if (c == 'x' || c == 'X')
1096  {
1097  --p;
1098  #ifndef SMALL_SCANF
1099  /*(void)*/ ungetc (c, fp);
1100  #else
1101  __io_ungetc (c);
1102  #endif
1103 
1104  }
1105  if ((flags & SUPPRESS) == 0)
1106  {
1107  u_long res;
1108 
1109  *p = 0;
1110  res = (*ccfn) (rptr, buf, (char **) NULL, base);
1111  if (flags & POINTER)
1112  *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
1113  else if (flags & CHAR)
1114  {
1115  cp = va_arg (ap, char *);
1116  *cp = res;
1117  }
1118  else if (flags & SHORT)
1119  {
1120  sp = va_arg (ap, short *);
1121  *sp = res;
1122  }
1123  else if (flags & LONG)
1124  {
1125  lp = va_arg (ap, long *);
1126  *lp = res;
1127  }
1128 #ifndef _NO_LONGLONG
1129  else if (flags & LONGDBL)
1130  {
1131  u_long_long resll;
1132  if (ccfn == _strtoul_r)
1133  resll = _strtoull_r (rptr, buf, (char **) NULL, base);
1134  else
1135  resll = _strtoll_r (rptr, buf, (char **) NULL, base);
1136  llp = va_arg (ap, long long*);
1137  *llp = resll;
1138  }
1139 #endif
1140  else
1141  {
1142  ip = va_arg (ap, int *);
1143  *ip = res;
1144  }
1145  nassigned++;
1146  }
1147  nread += p - buf;
1148  break;
1149 
1150 #ifdef FLOATING_POINT
1151  case CT_FLOAT:
1152  {
1153  /* scan a floating point number as if by strtod */
1154  /* This code used to assume that the number of digits is reasonable.
1155  However, ANSI / ISO C makes no such stipulation; we have to get
1156  exact results even when there is an unreasonable amount of
1157  leading zeroes. */
1158  long leading_zeroes = 0;
1159  long zeroes, exp_adjust;
1160  char *exp_start = NULL;
1161 #ifdef hardway
1162  if (width == 0 || width > sizeof (buf) - 1)
1163  width = sizeof (buf) - 1;
1164 #else
1165  /* size_t is unsigned, hence this optimisation */
1166  if (--width > sizeof (buf) - 2)
1167  width = sizeof (buf) - 2;
1168  width++;
1169 #endif
1170  flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1171  zeroes = 0;
1172  exp_adjust = 0;
1173  for (p = buf; width; )
1174  {
1175  c = *fp->_p;
1176  /*
1177  * This code mimicks the integer conversion
1178  * code, but is much simpler.
1179  */
1180  switch (c)
1181  {
1182 
1183  case '0':
1184  if (flags & NDIGITS)
1185  {
1186  flags &= ~SIGNOK;
1187  zeroes++;
1188  goto fskip;
1189  }
1190  /* Fall through. */
1191  case '1':
1192  case '2':
1193  case '3':
1194  case '4':
1195  case '5':
1196  case '6':
1197  case '7':
1198  case '8':
1199  case '9':
1200  flags &= ~(SIGNOK | NDIGITS);
1201  goto fok;
1202 
1203  case '+':
1204  case '-':
1205  if (flags & SIGNOK)
1206  {
1207  flags &= ~SIGNOK;
1208  goto fok;
1209  }
1210  break;
1211  case '.':
1212  if (flags & DPTOK)
1213  {
1214  flags &= ~(SIGNOK | DPTOK);
1215  leading_zeroes = zeroes;
1216  goto fok;
1217  }
1218  break;
1219  case 'e':
1220  case 'E':
1221  /* no exponent without some digits */
1222  if ((flags & (NDIGITS | EXPOK)) == EXPOK
1223  || ((flags & EXPOK) && zeroes))
1224  {
1225  if (! (flags & DPTOK))
1226  {
1227  exp_adjust = zeroes - leading_zeroes;
1228  exp_start = p;
1229  }
1230  flags =
1231  (flags & ~(EXPOK | DPTOK)) |
1232  SIGNOK | NDIGITS;
1233  zeroes = 0;
1234  goto fok;
1235  }
1236  break;
1237  }
1238  break;
1239  fok:
1240  *p++ = c;
1241  fskip:
1242  width--;
1243  ++nread;
1244  #ifndef SMALL_SCANF
1245  if (--fp->_r > 0)
1246  fp->_p++;
1247  else
1248  if (__srefill (fp))
1249  break; /* EOF */
1250  #else
1251  *fp->_p = new_getchar();
1252  if ( (47<*fp->_p<58) && (64<*fp->_p < 71) && (96<*fp->_p<103) ){
1253  ;
1254  }
1255  else
1256  {
1257  break;
1258  }
1259  #endif
1260  }
1261  if (zeroes)
1262  flags &= ~NDIGITS;
1263  /*
1264  * If no digits, might be missing exponent digits
1265  * (just give back the exponent) or might be missing
1266  * regular digits, but had sign and/or decimal point.
1267  */
1268  if (flags & NDIGITS)
1269  {
1270  if (flags & EXPOK)
1271  {
1272  /* no digits at all */
1273 
1274  while (p > buf)
1275  {
1276  #ifndef SMALL_SCANF
1277  ungetc (*(u_char *)-- p, fp);
1278  #else
1279  __io_ungetc(*(u_char *)-- p);
1280  #endif
1281  --nread;
1282  }
1283 
1284  goto match_failure;
1285 
1286  }
1287 
1288  /* just a bad exponent (e and maybe sign) */
1289  c = *(u_char *)-- p;
1290  --nread;
1291  if (c != 'e' && c != 'E')
1292  {
1293  #ifndef SMALL_SCANF
1294  _CAST_VOID ungetc (c, fp); /* sign */
1295  #else
1296  _CAST_VOID __io_ungetc (c);
1297  #endif
1298  c = *(u_char *)-- p;
1299  --nread;
1300  }
1301  #ifndef SMALL_SCANF
1302  _CAST_VOID ungetc (c, fp);
1303  #else
1304  _CAST_VOID __io_ungetc (c);
1305  #endif
1306 
1307  }
1308  if ((flags & SUPPRESS) == 0)
1309  {
1310  double res = 0;
1311 #ifdef _NO_LONGDBL
1312 #define QUAD_RES res;
1313 #else /* !_NO_LONG_DBL */
1314  long double qres = 0;
1315 #define QUAD_RES qres;
1316 #endif /* !_NO_LONG_DBL */
1317  long new_exp = 0;
1318 
1319  *p = 0;
1320  if ((flags & (DPTOK | EXPOK)) == EXPOK)
1321  {
1322  exp_adjust = zeroes - leading_zeroes;
1323  new_exp = -exp_adjust;
1324  exp_start = p;
1325  }
1326  else if (exp_adjust)
1327  new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1328  if (exp_adjust)
1329  {
1330 
1331  /* If there might not be enough space for the new exponent,
1332  truncate some trailing digits to make room. */
1333  if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
1334  exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
1335  sprintf (exp_start, "e%ld", new_exp);
1336  }
1337 
1338  /* Current _strtold routine is markedly slower than
1339  _strtod_r. Only use it if we have a long double
1340  result. */
1341 #ifndef _NO_LONGDBL /* !_NO_LONGDBL */
1342  if (flags & LONGDBL)
1343  qres = _strtold (buf, NULL);
1344  else
1345 #endif
1346  res = _strtod_r (rptr, buf, NULL);
1347  if (flags & LONG)
1348  {
1349  dp = va_arg (ap, double *);
1350  *dp = res;
1351  }
1352  else if (flags & LONGDBL)
1353  {
1354  ldp = va_arg (ap, _LONG_DOUBLE *);
1355  *ldp = QUAD_RES;
1356  }
1357  else
1358  {
1359  flp = va_arg (ap, float *);
1360  *flp = res;
1361  }
1362  nassigned++;
1363  }
1364  break;
1365  }
1366 #endif /* FLOATING_POINT */
1367 
1368  }
1369  }
1370 input_failure:
1371  return nassigned ? nassigned : -1;
1372 match_failure:
1373  return nassigned;
1374 }
1375 
1376 /*
1377  * Fill in the given table from the scanset at the given format
1378  * (just after `['). Return a pointer to the character past the
1379  * closing `]'. The table has a 1 wherever characters should be
1380  * considered part of the scanset.
1381  */
1382 
1383 /*static*/
1384 u_char *
1385 __sccl (tab, fmt)
1386  register char *tab;
1387  register u_char *fmt;
1388 {
1389  register int c, n, v;
1390 
1391  /* first `clear' the whole table */
1392  c = *fmt++; /* first char hat => negated scanset */
1393  if (c == '^')
1394  {
1395  v = 1; /* default => accept */
1396  c = *fmt++; /* get new first char */
1397  }
1398  else
1399  v = 0; /* default => reject */
1400  /* should probably use memset here */
1401  for (n = 0; n < 256; n++)
1402  tab[n] = v;
1403  if (c == 0)
1404  return fmt - 1; /* format ended before closing ] */
1405 
1406  /*
1407  * Now set the entries corresponding to the actual scanset to the
1408  * opposite of the above.
1409  *
1410  * The first character may be ']' (or '-') without being special; the
1411  * last character may be '-'.
1412  */
1413 
1414  v = 1 - v;
1415  for (;;)
1416  {
1417  tab[c] = v; /* take character c */
1418  doswitch:
1419  n = *fmt++; /* and examine the next */
1420  switch (n)
1421  {
1422 
1423  case 0: /* format ended too soon */
1424  return fmt - 1;
1425 
1426  case '-':
1427  /*
1428  * A scanset of the form [01+-] is defined as `the digit 0, the
1429  * digit 1, the character +, the character -', but the effect of a
1430  * scanset such as [a-zA-Z0-9] is implementation defined. The V7
1431  * Unix scanf treats `a-z' as `the letters a through z', but treats
1432  * `a-a' as `the letter a, the character -, and the letter a'.
1433  *
1434  * For compatibility, the `-' is not considerd to define a range if
1435  * the character following it is either a close bracket (required by
1436  * ANSI) or is not numerically greater than the character we just
1437  * stored in the table (c).
1438  */
1439  n = *fmt;
1440  if (n == ']' || n < c)
1441  {
1442  c = '-';
1443  break; /* resume the for(;;) */
1444  }
1445  fmt++;
1446  do
1447  { /* fill in the range */
1448  tab[++c] = v;
1449  }
1450  while (c < n);
1451 #if 1 /* XXX another disgusting compatibility hack */
1452  /*
1453  * Alas, the V7 Unix scanf also treats formats such
1454  * as [a-c-e] as `the letters a through e'. This too
1455  * is permitted by the standard....
1456  */
1457  goto doswitch;
1458 #else
1459  c = *fmt++;
1460  if (c == 0)
1461  return fmt - 1;
1462  if (c == ']')
1463  return fmt;
1464 #endif
1465 
1466  break;
1467 
1468 
1469  case ']': /* end of scanset */
1470  return fmt;
1471 
1472  default: /* just another character */
1473  c = n;
1474  break;
1475  }
1476  }
1477  /* NOTREACHED */
1478 }
1479 
1480 
1481