summaryrefslogtreecommitdiffstats
path: root/newlib/libc/stdio/nano-vfscanf.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/stdio/nano-vfscanf.c')
-rw-r--r--newlib/libc/stdio/nano-vfscanf.c497
1 files changed, 497 insertions, 0 deletions
diff --git a/newlib/libc/stdio/nano-vfscanf.c b/newlib/libc/stdio/nano-vfscanf.c
new file mode 100644
index 000000000..6a827567a
--- /dev/null
+++ b/newlib/libc/stdio/nano-vfscanf.c
@@ -0,0 +1,497 @@
+/*-
+ * 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
+<<vfscanf>>, <<vscanf>>, <<vsscanf>>---format argument list
+
+INDEX
+ vfscanf
+INDEX
+ _vfscanf_r
+INDEX
+ vscanf
+INDEX
+ _vscanf_r
+INDEX
+ vsscanf
+INDEX
+ _vsscanf_r
+
+ANSI_SYNOPSIS
+ #include <stdio.h>
+ #include <stdarg.h>
+ 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]>);
+
+TRAD_SYNOPSIS
+ #include <stdio.h>
+ #include <varargs.h>
+ int vscanf( <[fmt]>, <[ist]>)
+ char *<[fmt]>;
+ va_list <[list]>;
+
+ int vfscanf( <[fp]>, <[fmt]>, <[list]>)
+ FILE *<[fp]>;
+ char *<[fmt]>;
+ va_list <[list]>;
+
+ int vsscanf( <[str]>, <[fmt]>, <[list]>)
+ char *<[str]>;
+ char *<[fmt]>;
+ va_list <[list]>;
+
+ int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
+ struct _reent *<[reent]>;
+ char *<[fmt]>;
+ va_list <[list]>;
+
+ int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
+ struct _reent *<[reent]>;
+ FILE *<[fp]>;
+ char *<[fmt]>;
+ va_list <[list]>;
+
+ int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
+ struct _reent *<[reent]>;
+ char *<[str]>;
+ char *<[fmt]>;
+ va_list <[list]>;
+
+DESCRIPTION
+<<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
+of <<scanf>>, <<fscanf>>, and <<sscanf>>. They differ only in
+allowing their caller to pass the variable argument list as a
+<<va_list>> object (initialized by <<va_start>>) rather than
+directly accepting a variable number of arguments.
+
+RETURNS
+The return values are consistent with the corresponding functions:
+<<vscanf>> returns the number of input fields successfully scanned,
+converted, and stored; the return value does not include scanned
+fields which were not stored.
+
+If <<vscanf>> attempts to read at end-of-file, the return value
+is <<EOF>>.
+
+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 <reent.h>
+#include <newlib.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include "local.h"
+#include "../stdlib/local.h"
+#include "nano-vfscanf_local.h"
+
+#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 _AND
+ _CONST char *fmt _AND
+ 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 _AND
+ char _CONST *fmt0 _AND
+ va_list ap)
+{
+ return __SVFSCANF_R (_REENT, fp, fmt0, ap);
+}
+
+#endif
+
+int
+_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, 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 _AND
+ int c _AND
+ 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 _AND
+ 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 *, _PTR buf, size_t, size_t, FILE *));
+#endif /* !STRING_ONLY. */
+
+int
+_DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
+ struct _reent *rptr _AND
+ register FILE *fp _AND
+ char _CONST *fmt0 _AND
+ 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':
+ 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 'f':
+ 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, &ap);
+ else if (scan_data.code < CT_FLOAT)
+ ret = _scanf_i (rptr, &scan_data, fp, &ap);
+#ifdef FLOATING_POINT
+ else if (_scanf_float)
+ ret = _scanf_float (rptr, &scan_data, fp, &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
+