/*- * 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. */ /* * Copyright (c) 2012-2014 ARM Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* FUNCTION <>, <>, <>---format argument list INDEX vfscanf INDEX _vfscanf_r INDEX vscanf INDEX _vscanf_r INDEX vsscanf INDEX _vsscanf_r SYNOPSIS #include #include int vscanf(const char *<[fmt]>, va_list <[list]>); 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]>, va_list <[list]>); int _vfscanf_r(struct _reent *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>); int _vsscanf_r(struct _reent *<[reent]>, const char *<[str]>, const char *<[fmt]>, va_list <[list]>); DESCRIPTION <>, <>, and <> are (respectively) variants of <>, <>, and <>. They differ only in allowing their caller to pass the variable argument list as a <> object (initialized by <>) rather than directly accepting a variable number of arguments. RETURNS The return values are consistent with the corresponding functions: <> returns the number of input fields successfully scanned, converted, and stored; the return value does not include scanned fields which were not stored. If <> attempts to read at end-of-file, the return value is <>. If no fields were stored, the return value is <<0>>. The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are reentrant versions which take an additional first parameter which points to the reentrancy structure. PORTABILITY These are GNU extensions. Supporting OS subroutines required: */ #include <_ansi.h> #include #include #include #include #include #include #include #include #include #include #include #include #include "local.h" #include "../stdlib/local.h" #include "nano-vfscanf_local.h" /* GCC PR 14577 at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557 */ #if __STDC_VERSION__ >= 201112L #define va_ptr(ap) _Generic(&(ap), va_list *: &(ap), default: (va_list *)(ap)) #elif __GNUC__ >= 4 #define va_ptr(ap) __builtin_choose_expr(__builtin_types_compatible_p(__typeof__(&(ap)), va_list *), &(ap), (va_list *)(ap)) #else #define va_ptr(ap) (sizeof(ap) == sizeof(va_list) ? (va_list *)&(ap) : (va_list *)(ap)) #endif #define VFSCANF vfscanf #define _VFSCANF_R _vfscanf_r #define __SVFSCANF __svfscanf #ifdef STRING_ONLY # define __SVFSCANF_R __ssvfscanf_r #else # define __SVFSCANF_R __svfscanf_r #endif /* vfscanf. */ #ifndef STRING_ONLY #ifndef _REENT_ONLY int _DEFUN(VFSCANF, (fp, fmt, ap), register FILE *fp, const char *fmt, va_list ap) { CHECK_INIT(_REENT, fp); return __SVFSCANF_R (_REENT, fp, fmt, ap); } int _EXFUN(vfiscanf, (FILE *, const char *, __VALIST) _ATTRIBUTE ((__alias__("vfscanf")))); int _DEFUN(__SVFSCANF, (fp, fmt0, ap), register FILE *fp, char const *fmt0, va_list ap) { return __SVFSCANF_R (_REENT, fp, fmt0, ap); } #endif int _DEFUN(_VFSCANF_R, (data, fp, fmt, ap), struct _reent *data, register FILE *fp, const char *fmt, va_list ap) { CHECK_INIT(data, fp); return __SVFSCANF_R (data, fp, fmt, ap); } int _EXFUN(_vfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST) _ATTRIBUTE ((__alias__("_vfscanf_r")))); #endif /* !STRING_ONLY. */ #if defined (STRING_ONLY) /* When dealing with the sscanf family, we don't want to use the regular ungetc which will drag in file I/O items we don't need. So, we create our own trimmed-down version. */ int _DEFUN(_sungetc_r, (data, fp, ch), struct _reent *data, int c, register FILE *fp) { if (c == EOF) return (EOF); /* After ungetc, we won't be at eof anymore. */ fp->_flags &= ~__SEOF; c = (unsigned char) c; /* If we are in the middle of ungetc'ing, just continue. This may require expanding the current ungetc buffer. */ if (HASUB (fp)) { if (fp->_r >= fp->_ub._size && __submore (data, fp)) return EOF; *--fp->_p = c; fp->_r++; return c; } /* If we can handle this by simply backing up, do so, but never replace the original character. (This makes sscanf() work when scanning `const' data). */ if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && fp->_p[-1] == c) { fp->_p--; fp->_r++; return c; } /* Create an ungetc buffer. Initially, we will use the `reserve' buffer. */ fp->_ur = fp->_r; fp->_up = fp->_p; fp->_ub._base = fp->_ubuf; fp->_ub._size = sizeof (fp->_ubuf); fp->_ubuf[sizeof (fp->_ubuf) - 1] = c; fp->_p = &fp->_ubuf[sizeof (fp->_ubuf) - 1]; fp->_r = 1; return c; } /* String only version of __srefill_r for sscanf family. */ int _DEFUN(__ssrefill_r, (ptr, fp), struct _reent * ptr, register FILE * fp) { /* Our only hope of further input is the ungetc buffer. If there is anything in that buffer to read, return. */ if (HASUB (fp)) { FREEUB (ptr, fp); if ((fp->_r = fp->_ur) != 0) { fp->_p = fp->_up; return 0; } } /* Otherwise we are out of character input. */ fp->_p = fp->_bf._base; fp->_r = 0; fp->_flags |= __SEOF; return EOF; } #else int _EXFUN (_sungetc_r, (struct _reent *, int, register FILE *)); int _EXFUN (__ssrefill_r, (struct _reent *, register FILE *)); size_t _EXFUN (_sfread_r, (struct _reent *, void *buf, size_t, size_t, FILE *)); #endif /* !STRING_ONLY. */ int _DEFUN(__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. */ register char *p; /* Points into all kinds of strings. */ char ccltab[256]; /* Character class table for %[...]. */ int ret; char *cp; struct _scan_data_t scan_data; int (*scan_func)(struct _reent*, struct _scan_data_t*, FILE *, va_list *); _newlib_flockfile_start (fp); scan_data.nassigned = 0; scan_data.nread = 0; scan_data.ccltab = ccltab; scan_data.pfn_ungetc = _ungetc_r; scan_data.pfn_refill = __srefill_r; for (;;) { if (*fmt == 0) goto all_done; if (isspace (*fmt)) { while ((fp->_r > 0 || !scan_data.pfn_refill(rptr, fp)) && isspace (*fp->_p)) { scan_data.nread++; fp->_r--; fp->_p++; } fmt++; continue; } if ((c = *fmt++) != '%') goto literal; scan_data.width = 0; scan_data.flags = 0; if (*fmt == '*') { scan_data.flags |= SUPPRESS; fmt++; } for (; is_digit (*fmt); fmt++) scan_data.width = 10 * scan_data.width + to_digit (*fmt); /* The length modifiers. */ p = "hlL"; if ((cp = memchr (p, *fmt, 3)) != NULL) { scan_data.flags |= (SHORT << (cp - p)); fmt++; } /* Switch on the format. continue if done; break once format type is derived. */ c = *fmt++; switch (c) { case '%': literal: if ((fp->_r <= 0 && scan_data.pfn_refill(rptr, fp))) goto input_failure; if (*fp->_p != c) goto match_failure; fp->_r--, fp->_p++; scan_data.nread++; continue; case 'p': scan_data.flags |= POINTER; case 'x': case 'X': scan_data.flags |= PFXOK; scan_data.base = 16; goto number; case 'd': case 'u': scan_data.base = 10; goto number; case 'i': scan_data.base = 0; goto number; case 'o': scan_data.base = 8; number: scan_data.code = (c < 'o') ? CT_INT : CT_UINT; break; case '[': fmt = (u_char *) __sccl (ccltab, (unsigned char *) fmt); scan_data.flags |= NOSKIP; scan_data.code = CT_CCL; break; case 'c': scan_data.flags |= NOSKIP; scan_data.code = CT_CHAR; break; case 's': scan_data.code = CT_STRING; break; case 'n': if (scan_data.flags & SUPPRESS) /* ??? */ continue; if (scan_data.flags & SHORT) *GET_ARG (N, ap, short *) = scan_data.nread; else if (scan_data.flags & LONG) *GET_ARG (N, ap, long *) = scan_data.nread; else *GET_ARG (N, ap, int *) = scan_data.nread; continue; /* Disgusting backwards compatibility hacks. XXX. */ case '\0': /* compat. */ _newlib_flockfile_exit (fp); return EOF; #ifdef FLOATING_POINT case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': scan_data.code = CT_FLOAT; break; #endif default: /* compat. */ scan_data.code = CT_INT; scan_data.base = 10; break; } /* We have a conversion that requires input. */ if ((fp->_r <= 0 && scan_data.pfn_refill (rptr, fp))) goto input_failure; /* Consume leading white space, except for formats that suppress this. */ if ((scan_data.flags & NOSKIP) == 0) { while (isspace (*fp->_p)) { scan_data.nread++; if (--fp->_r > 0) fp->_p++; else if (scan_data.pfn_refill (rptr, fp)) goto input_failure; } /* Note that there is at least one character in the buffer, so conversions that do not set NOSKIP ca no longer result in an input failure. */ } ret = 0; if (scan_data.code < CT_INT) ret = _scanf_chars (rptr, &scan_data, fp, va_ptr(ap)); else if (scan_data.code < CT_FLOAT) ret = _scanf_i (rptr, &scan_data, fp, va_ptr(ap)); #ifdef FLOATING_POINT else if (_scanf_float) ret = _scanf_float (rptr, &scan_data, fp, va_ptr(ap)); #endif if (ret == MATCH_FAILURE) goto match_failure; else if (ret == INPUT_FAILURE) goto input_failure; } input_failure: /* On read failure, return EOF failure regardless of matches; errno should have been set prior to here. On EOF failure (including invalid format string), return EOF if no matches yet, else number of matches made prior to failure. */ _newlib_flockfile_exit (fp); return scan_data.nassigned && !(fp->_flags & __SERR) ? scan_data.nassigned : EOF; match_failure: all_done: /* Return number of matches, which can be 0 on match failure. */ _newlib_flockfile_end (fp); return scan_data.nassigned; } #ifdef STRING_ONLY int _EXFUN(__ssvfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST) _ATTRIBUTE ((__alias__("__ssvfscanf_r")))); #else int _EXFUN(__svfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST) _ATTRIBUTE ((__alias__("__svfscanf_r")))); #endif