diff options
Diffstat (limited to 'newlib/libc/stdio/vfscanf.c')
-rw-r--r-- | newlib/libc/stdio/vfscanf.c | 582 |
1 files changed, 243 insertions, 339 deletions
diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c index 4788938c9..8f49141f1 100644 --- a/newlib/libc/stdio/vfscanf.c +++ b/newlib/libc/stdio/vfscanf.c @@ -1,20 +1,3 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - /* FUNCTION <<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list @@ -33,12 +16,12 @@ ANSI_SYNOPSIS int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>); int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>); - int _vscanf_r(struct _reent *<[reent]>, const char *<[fmt]>, + int _vscanf_r(void *<[reent]>, const char *<[fmt]>, va_list <[list]>); - int _vfscanf_r(struct _reent *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, + int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, + va_list <[list]>); + int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[fmt]>, va_list <[list]>); - int _vsscanf_r(struct _reent *<[reent]>, const char *<[str]>, - const char *<[fmt]>, va_list <[list]>); TRAD_SYNOPSIS #include <stdio.h> @@ -58,18 +41,18 @@ TRAD_SYNOPSIS va_list <[list]>; int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>) - struct _reent *<[reent]>; + char *<[reent]>; char *<[fmt]>; va_list <[list]>; int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>) - struct _reent *<[reent]>; + char *<[reent]>; FILE *<[fp]>; char *<[fmt]>; va_list <[list]>; int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>) - struct _reent *<[reent]>; + char *<[reent]>; char *<[str]>; char *<[fmt]>; va_list <[list]>; @@ -102,16 +85,28 @@ These are GNU extensions. Supporting OS subroutines required: */ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include <_ansi.h> -#include <reent.h> -#include <newlib.h> #include <ctype.h> -#include <wctype.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> -#include <wchar.h> -#include <string.h> #ifdef _HAVE_STDC #include <stdarg.h> #else @@ -119,42 +114,29 @@ Supporting OS subroutines required: #endif #include "local.h" -#ifdef INTEGER_ONLY -#define VFSCANF vfiscanf -#define _VFSCANF_R _vfiscanf_r -#define __SVFSCANF __svfiscanf -#define __SVFSCANF_R __svfiscanf_r -#else -#define VFSCANF vfscanf -#define _VFSCANF_R _vfscanf_r -#define __SVFSCANF __svfscanf -#define __SVFSCANF_R __svfscanf_r -#ifndef NO_FLOATING_POINT +#ifndef NO_FLOATING_POINT #define FLOATING_POINT #endif -#endif #ifdef FLOATING_POINT -#include <math.h> #include <float.h> /* Currently a test is made to see if long double processing is warranted. This could be changed in the future should the _ldtoa_r code be preferred over _dtoa_r. */ #define _NO_LONGDBL -#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG) +#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG) #undef _NO_LONGDBL extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); #endif -#include "floatio.h" - -#if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX) -# define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ -#else -# define BUF MB_LEN_MAX +#define _NO_LONGLONG +#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__ +# undef _NO_LONGLONG #endif +#include "floatio.h" +#define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ /* An upper bound for how long a long prints in decimal. 4 / 13 approximates log (2). Add one char for roundoff compensation and one for the sign. */ #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2) @@ -162,22 +144,16 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); #define BUF 40 #endif -#define _NO_LONGLONG -#if defined _WANT_IO_LONG_LONG && defined __GNUC__ -# undef _NO_LONGLONG -#endif - /* * Flags used during conversion. */ #define LONG 0x01 /* l: long or double */ -#define LONGDBL 0x02 /* L/ll: long double or long long */ +#define LONGDBL 0x02 /* L: long double or long long */ #define SHORT 0x04 /* h: short */ -#define CHAR 0x08 /* hh: 8 bit integer */ -#define SUPPRESS 0x10 /* suppress assignment */ -#define POINTER 0x20 /* weird %p pointer (`fake hex') */ -#define NOSKIP 0x40 /* do not skip blanks */ +#define SUPPRESS 0x08 /* suppress assignment */ +#define POINTER 0x10 /* weird %p pointer (`fake hex') */ +#define NOSKIP 0x20 /* do not skip blanks */ /* * The following are used in numeric conversions only: @@ -185,15 +161,14 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. */ -#define SIGNOK 0x80 /* +/- is (still) legal */ -#define NDIGITS 0x100 /* no digits detected */ +#define SIGNOK 0x40 /* +/- is (still) legal */ +#define NDIGITS 0x80 /* no digits detected */ -#define DPTOK 0x200 /* (float) decimal point is still legal */ -#define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */ +#define DPTOK 0x100 /* (float) decimal point is still legal */ +#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ -#define PFXOK 0x200 /* 0x prefix is (still) legal */ -#define NZDIGITS 0x400 /* no zero digits detected */ -#define NNZDIGITS 0x800 /* no non-zero digits detected */ +#define PFXOK 0x100 /* 0x prefix is (still) legal */ +#define NZDIGITS 0x200 /* no zero digits detected */ /* * Conversion types. @@ -226,44 +201,43 @@ typedef unsigned long long u_long_long; #ifndef _REENT_ONLY int -_DEFUN(VFSCANF, (fp, fmt, ap), - register FILE *fp _AND - _CONST char *fmt _AND - va_list ap) +_DEFUN (vfscanf, (fp, fmt, ap), + register FILE *fp _AND + _CONST char *fmt _AND + va_list ap) { - CHECK_INIT(_REENT); - return __SVFSCANF_R (_REENT, fp, fmt, ap); + CHECK_INIT(fp); + return __svfscanf_r (fp->_data, fp, fmt, ap); } int -_DEFUN(__SVFSCANF, (fp, fmt0, ap), - register FILE *fp _AND - char _CONST *fmt0 _AND - va_list ap) +__svfscanf (fp, fmt0, ap) + register FILE *fp; + char _CONST *fmt0; + va_list ap; { - return __SVFSCANF_R (_REENT, fp, fmt0, ap); + return __svfscanf_r (_REENT, fp, fmt0, ap); } #endif /* !_REENT_ONLY */ int -_DEFUN(_VFSCANF_R, (data, fp, fmt, ap), - struct _reent *data _AND - register FILE *fp _AND - _CONST char *fmt _AND - va_list ap) +_DEFUN (_vfscanf_r, (data, fp, fmt, ap), + struct _reent *data _AND + register FILE *fp _AND + _CONST char *fmt _AND + va_list ap) { - CHECK_INIT(data); - return __SVFSCANF_R (data, fp, fmt, ap); + return __svfscanf_r (data, fp, fmt, ap); } int -_DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), - struct _reent *rptr _AND - register FILE *fp _AND - char _CONST *fmt0 _AND - va_list ap) +__svfscanf_r (rptr, fp, fmt0, ap) + struct _reent *rptr; + register FILE *fp; + char _CONST *fmt0; + va_list ap; { register u_char *fmt = (u_char *) fmt0; register int c; /* character from format, or conversion */ @@ -277,16 +251,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), int base = 0; /* base argument to strtol/strtoul */ int nbytes = 1; /* number of bytes read from fmt string */ wchar_t wc; /* wchar to use to read format string */ - wchar_t *wcp; /* handy wide character pointer */ - size_t mbslen; /* length of converted multibyte sequence */ - mbstate_t state; /* value to keep track of multibyte state */ u_long (*ccfn) () = 0; /* conversion function (strtol/strtoul) */ char ccltab[256]; /* character class table for %[...] */ char buf[BUF]; /* buffer for numeric conversions */ char *lptr; /* literal pointer */ +#ifdef MB_CAPABLE + int state = 0; /* value to keep track of multibyte state */ +#endif - char *cp; short *sp; int *ip; float *flp; @@ -295,32 +268,33 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), long *lp; #ifndef _NO_LONGLONG long long *llp; +#else + u_long _uquad; #endif /* `basefix' is used to avoid `if' tests in the integer scanner */ static _CONST short basefix[17] = {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - _flockfile (fp); - nassigned = 0; nread = 0; for (;;) { -#ifndef _MB_CAPABLE +#ifndef MB_CAPABLE wc = *fmt; #else - memset (&state, '\0', sizeof (state)); nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state); #endif fmt += nbytes; if (wc == 0) - goto all_done; + return nassigned; if (nbytes == 1 && isspace (wc)) { for (;;) { - if (BufferEmpty || !isspace (*fp->_p)) + if (BufferEmpty) + return nassigned; + if (!isspace (*fp->_p)) break; nread++, fp->_r--, fp->_p++; } @@ -360,25 +334,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), flags |= SUPPRESS; goto again; case 'l': - if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */ - { - ++fmt; - flags |= LONGDBL; - } - else - flags |= LONG; + flags |= LONG; goto again; case 'L': flags |= LONGDBL; goto again; case 'h': - if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */ - { - ++fmt; - flags |= CHAR; - } - else - flags |= SHORT; + flags |= SHORT; goto again; case '0': @@ -451,9 +413,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), c = CT_FLOAT; break; #endif - case 'S': - flags |= LONG; - /* FALLTHROUGH */ case 's': c = CT_STRING; @@ -465,10 +424,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), c = CT_CCL; break; - case 'C': - flags |= LONG; - /* FALLTHROUGH */ - case 'c': flags |= NOSKIP; c = CT_CHAR; @@ -484,12 +439,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), case 'n': if (flags & SUPPRESS) /* ??? */ continue; - if (flags & CHAR) - { - cp = va_arg (ap, char *); - *cp = nread; - } - else if (flags & SHORT) + if (flags & SHORT) { sp = va_arg (ap, short *); *sp = nread; @@ -517,7 +467,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), * Disgusting backwards compatibility hacks. XXX */ case '\0': /* compat */ - _funlockfile (fp); return EOF; default: /* compat */ @@ -547,7 +496,9 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), if (--fp->_r > 0) fp->_p++; else +#ifndef CYGNUS_NEC if (__srefill (fp)) +#endif goto input_failure; } /* @@ -567,47 +518,10 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), /* scan arbitrary characters (sets NOSKIP) */ if (width == 0) width = 1; - if (flags & LONG) - { - if ((flags & SUPPRESS) == 0) - wcp = va_arg (ap, wchar_t *); - else - wcp = NULL; - n = 0; - while (width != 0) - { - if (n == MB_CUR_MAX) - goto input_failure; - buf[n++] = *fp->_p; - fp->_r -= 1; - fp->_p += 1; - memset ((_PTR)&state, '\0', sizeof (mbstate_t)); - if ((mbslen = _mbrtowc_r (rptr, wcp, buf, n, &state)) - == (size_t)-1) - goto input_failure; /* Invalid sequence */ - if (mbslen == 0 && !(flags & SUPPRESS)) - *wcp = L'\0'; - if (mbslen != (size_t)-2) /* Incomplete sequence */ - { - nread += n; - width -= 1; - if (!(flags & SUPPRESS)) - wcp += 1; - n = 0; - } - if (BufferEmpty) - { - if (n != 0) - goto input_failure; - break; - } - } - if (!(flags & SUPPRESS)) - nassigned++; - } - else if (flags & SUPPRESS) + if (flags & SUPPRESS) { size_t sum = 0; + for (;;) { if ((n = fp->_r) < (int)width) @@ -615,12 +529,16 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), sum += n; width -= n; fp->_p += n; +#ifndef CYGNUS_NEC if (__srefill (fp)) { +#endif if (sum == 0) goto input_failure; break; +#ifndef CYGNUS_NEC } +#endif } else { @@ -634,11 +552,27 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } else { +#ifdef CYGNUS_NEC + /* Kludge city for the moment */ + char *dest = va_arg (ap, char *); + int n = width; + if (fp->_r == 0) + goto input_failure; + + while (n && fp->_r) + { + *dest++ = *(fp->_p++); + n--; + fp->_r--; + nread++; + } +#else size_t r = fread ((_PTR) va_arg (ap, char *), 1, width, fp); if (r == 0) goto input_failure; nread += r; +#endif nassigned++; } break; @@ -694,56 +628,8 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), case CT_STRING: /* like CCL, but zero-length string OK, & no NOSKIP */ if (width == 0) - width = (size_t)~0; - if (flags & LONG) - { - /* Process %S and %ls placeholders */ - if ((flags & SUPPRESS) == 0) - wcp = va_arg (ap, wchar_t *); - else - wcp = &wc; - n = 0; - while (!isspace (*fp->_p) && width != 0) - { - if (n == MB_CUR_MAX) - goto input_failure; - buf[n++] = *fp->_p; - fp->_r -= 1; - fp->_p += 1; - memset ((_PTR)&state, '\0', sizeof (mbstate_t)); - if ((mbslen = _mbrtowc_r (rptr, wcp, buf, n, &state)) - == (size_t)-1) - goto input_failure; - if (mbslen == 0) - *wcp = L'\0'; - if (mbslen != (size_t)-2) /* Incomplete sequence */ - { - if (iswspace(*wcp)) - { - while (n != 0) - ungetc (buf[--n], fp); - break; - } - nread += n; - width -= 1; - if ((flags & SUPPRESS) == 0) - wcp += 1; - n = 0; - } - if (BufferEmpty) - { - if (n != 0) - goto input_failure; - break; - } - } - if (!(flags & SUPPRESS)) - { - *wcp = L'\0'; - nassigned++; - } - } - else if (flags & SUPPRESS) + width = ~0; + if (flags & SUPPRESS) { n = 0; while (!isspace (*fp->_p)) @@ -775,21 +661,17 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), continue; case CT_INT: - { /* scan an integer as if by strtol/strtoul */ - unsigned width_left = 0; - int skips = 0; #ifdef hardway if (width == 0 || width > sizeof (buf) - 1) + width = sizeof (buf) - 1; #else /* size_t is unsigned, hence this optimisation */ - if (width - 1 > sizeof (buf) - 2) + if (--width > sizeof (buf) - 2) + width = sizeof (buf) - 2; + width++; #endif - { - width_left = width - (sizeof (buf) - 1); - width = sizeof (buf) - 1; - } - flags |= SIGNOK | NDIGITS | NZDIGITS | NNZDIGITS; + flags |= SIGNOK | NDIGITS | NZDIGITS; for (p = buf; width; width--) { c = *fp->_p; @@ -809,26 +691,16 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), * will turn it off if we have scanned any nonzero digits). */ case '0': - if (! (flags & NNZDIGITS)) - goto ok; if (base == 0) { base = 8; flags |= PFXOK; } if (flags & NZDIGITS) - { - flags &= ~(SIGNOK | NZDIGITS | NDIGITS); - goto ok; - } - flags &= ~(SIGNOK | PFXOK | NDIGITS); - if (width_left) - { - width_left--; - width++; - } - ++skips; - goto skip; + flags &= ~(SIGNOK | NZDIGITS | NDIGITS); + else + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; /* 1 through 7 always legal */ case '1': @@ -839,7 +711,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), case '6': case '7': base = basefix[base]; - flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS); + flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; /* digits 8 and 9 ok iff decimal or hex */ @@ -848,7 +720,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), base = basefix[base]; if (base <= 8) break; /* not legal here */ - flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS); + flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; /* letters ok iff hex */ @@ -867,7 +739,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), /* no need to fix base here */ if (base <= 10) break; /* not legal here */ - flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS); + flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; /* sign ok only as first character */ @@ -887,10 +759,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), { base = 16;/* if %i */ flags &= ~PFXOK; - /* We must reset the NZDIGITS and NDIGITS - flags that would have been unset by seeing - the zero that preceded the X or x. */ - flags |= NZDIGITS | NDIGITS; goto ok; } break; @@ -906,11 +774,12 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), * c is legal: store it and look at the next. */ *p++ = c; - skip: if (--fp->_r > 0) fp->_p++; else +#ifndef CYGNUS_NEC if (__srefill (fp)) +#endif break; /* EOF */ } /* @@ -938,11 +807,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), res = (*ccfn) (rptr, buf, (char **) NULL, base); if (flags & POINTER) *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res; - else if (flags & CHAR) - { - cp = va_arg (ap, char *); - *cp = res; - } else if (flags & SHORT) { sp = va_arg (ap, short *); @@ -972,9 +836,9 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } nassigned++; } - nread += p - buf + skips; + nread += p - buf; break; - } + #ifdef FLOATING_POINT case CT_FLOAT: { @@ -986,18 +850,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), long leading_zeroes = 0; long zeroes, exp_adjust; char *exp_start = NULL; - unsigned width_left = 0; - int nancount = 0; #ifdef hardway if (width == 0 || width > sizeof (buf) - 1) + width = sizeof (buf) - 1; #else /* size_t is unsigned, hence this optimisation */ - if (width - 1 > sizeof (buf) - 2) + if (--width > sizeof (buf) - 2) + width = sizeof (buf) - 2; + width++; #endif - { - width_left = width - (sizeof (buf) - 1); - width = sizeof (buf) - 1; - } flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; zeroes = 0; exp_adjust = 0; @@ -1010,16 +871,12 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), */ switch (c) { + case '0': if (flags & NDIGITS) { flags &= ~SIGNOK; zeroes++; - if (width_left) - { - width_left--; - width++; - } goto fskip; } /* Fall through. */ @@ -1032,12 +889,8 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), case '7': case '8': case '9': - if (nancount == 0) - { - flags &= ~(SIGNOK | NDIGITS); - goto fok; - } - break; + flags &= ~(SIGNOK | NDIGITS); + goto fok; case '+': case '-': @@ -1047,30 +900,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), goto fok; } break; - case 'n': - case 'N': - if (nancount == 0 - && (flags & (SIGNOK | NDIGITS | DPTOK | EXPOK)) == - (SIGNOK | NDIGITS | DPTOK | EXPOK)) - { - flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS); - nancount = 1; - goto fok; - } - else if (nancount == 2) - { - nancount = 3; - goto fok; - } - break; - case 'a': - case 'A': - if (nancount == 1) - { - nancount = 2; - goto fok; - } - break; case '.': if (flags & DPTOK) { @@ -1101,35 +930,20 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), break; fok: *p++ = c; - fskip: width--; + fskip: ++nread; if (--fp->_r > 0) fp->_p++; else +#ifndef CYGNUS_NEC if (__srefill (fp)) +#endif break; /* EOF */ } if (zeroes) flags &= ~NDIGITS; - /* We may have a 'N' or possibly even a 'Na' as the start of 'NaN', - only to run out of chars before it was complete (or having - encountered a non- matching char). So check here if we have an - outstanding nancount, and if so put back the chars we did - swallow and treat as a failed match. */ - if (nancount && nancount != 3) - { - /* Ok... what are we supposed to do in the event that the - __srefill call above was triggered in the middle of the partial - 'NaN' and so we can't put it all back? */ - while (nancount-- && (p > buf)) - { - ungetc (*(u_char *)--p, fp); - --nread; - } - goto match_failure; - } - /* + /* * If no digits, might be missing exponent digits * (just give back the exponent) or might be missing * regular digits, but had sign and/or decimal point. @@ -1141,7 +955,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), /* no digits at all */ while (p > buf) { - ungetc (*(u_char *)--p, fp); + ungetc (*(u_char *)-- p, fp); --nread; } goto match_failure; @@ -1159,12 +973,10 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } if ((flags & SUPPRESS) == 0) { - double res = 0; #ifdef _NO_LONGDBL -#define QUAD_RES res; + double res; #else /* !_NO_LONG_DBL */ - long double qres = 0; -#define QUAD_RES qres; + long double res; #endif /* !_NO_LONG_DBL */ long new_exp = 0; @@ -1186,17 +998,11 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1; sprintf (exp_start, "e%ld", new_exp); } - - /* Current _strtold routine is markedly slower than - _strtod_r. Only use it if we have a long double - result. */ -#ifndef _NO_LONGDBL /* !_NO_LONGDBL */ - if (flags & LONGDBL) - qres = _strtold (buf, NULL); - else -#endif - res = _strtod_r (rptr, buf, NULL); - +#ifdef _NO_LONGDBL + res = _strtod_r (rptr, buf, NULL); +#else /* !_NO_LONGDBL */ + res = _strtold (buf, NULL); +#endif /* !_NO_LONGDBL */ if (flags & LONG) { dp = va_arg (ap, double *); @@ -1205,15 +1011,12 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), else if (flags & LONGDBL) { ldp = va_arg (ap, _LONG_DOUBLE *); - *ldp = QUAD_RES; + *ldp = res; } else { flp = va_arg (ap, float *); - if (isnan (res)) - *flp = nanf (NULL); - else - *flp = res; + *flp = res; } nassigned++; } @@ -1223,10 +1026,111 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } } input_failure: - _funlockfile (fp); return nassigned ? nassigned : -1; match_failure: -all_done: - _funlockfile (fp); return nassigned; } + +/* + * Fill in the given table from the scanset at the given format + * (just after `['). Return a pointer to the character past the + * closing `]'. The table has a 1 wherever characters should be + * considered part of the scanset. + */ + +/*static*/ +u_char * +__sccl (tab, fmt) + register char *tab; + register u_char *fmt; +{ + register int c, n, v; + + /* first `clear' the whole table */ + c = *fmt++; /* first char hat => negated scanset */ + if (c == '^') + { + v = 1; /* default => accept */ + c = *fmt++; /* get new first char */ + } + else + v = 0; /* default => reject */ + /* should probably use memset here */ + for (n = 0; n < 256; n++) + tab[n] = v; + if (c == 0) + return fmt - 1; /* format ended before closing ] */ + + /* + * Now set the entries corresponding to the actual scanset to the + * opposite of the above. + * + * The first character may be ']' (or '-') without being special; the + * last character may be '-'. + */ + + v = 1 - v; + for (;;) + { + tab[c] = v; /* take character c */ + doswitch: + n = *fmt++; /* and examine the next */ + switch (n) + { + + case 0: /* format ended too soon */ + return fmt - 1; + + case '-': + /* + * A scanset of the form [01+-] is defined as `the digit 0, the + * digit 1, the character +, the character -', but the effect of a + * scanset such as [a-zA-Z0-9] is implementation defined. The V7 + * Unix scanf treats `a-z' as `the letters a through z', but treats + * `a-a' as `the letter a, the character -, and the letter a'. + * + * For compatibility, the `-' is not considerd to define a range if + * the character following it is either a close bracket (required by + * ANSI) or is not numerically greater than the character we just + * stored in the table (c). + */ + n = *fmt; + if (n == ']' || n < c) + { + c = '-'; + break; /* resume the for(;;) */ + } + fmt++; + do + { /* fill in the range */ + tab[++c] = v; + } + while (c < n); +#if 1 /* XXX another disgusting compatibility hack */ + /* + * Alas, the V7 Unix scanf also treats formats such + * as [a-c-e] as `the letters a through e'. This too + * is permitted by the standard.... + */ + goto doswitch; +#else + c = *fmt++; + if (c == 0) + return fmt - 1; + if (c == ']') + return fmt; +#endif + + break; + + + case ']': /* end of scanset */ + return fmt; + + default: /* just another character */ + c = n; + break; + } + } + /* NOTREACHED */ +} |