diff options
Diffstat (limited to 'newlib/libc/stdio/nano-vfscanf_i.c')
-rw-r--r-- | newlib/libc/stdio/nano-vfscanf_i.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/newlib/libc/stdio/nano-vfscanf_i.c b/newlib/libc/stdio/nano-vfscanf_i.c new file mode 100644 index 000000000..aba74b0d8 --- /dev/null +++ b/newlib/libc/stdio/nano-vfscanf_i.c @@ -0,0 +1,232 @@ +/* + * 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. + */ + +#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" + +int +_scanf_chars (struct _reent *rptr, + struct _scan_data_t *pdata, + FILE *fp, va_list *ap) +{ + int n; + char *p; + + if (pdata->width == 0) + pdata->width = (pdata->code == CT_CHAR) ? 1 : (size_t)~0; + + n = 0; + if ((pdata->flags & SUPPRESS) == 0) + p = GET_ARG (N, *ap, char *); + + /* It's impossible to have EOF when we get here. */ + while ((pdata->code == CT_CHAR) + || (pdata->code == CT_CCL && pdata->ccltab[*fp->_p]) + || (pdata->code == CT_STRING && !isspace (*fp->_p))) + { + n++; + if ((pdata->flags & SUPPRESS) == 0) + *p++ = *fp->_p; + + fp->_r--, fp->_p++; + if (--pdata->width == 0) + break; + + if ((fp->_r <= 0 && pdata->pfn_refill (rptr, fp))) + break; + } + /* For CT_CHAR, it is impossible to have input_failure(n == 0) here. + For CT_CCL, it is impossible to have input_failure here. + For CT_STRING, it is possible to have empty string. */ + if (n == 0 && pdata->code == CT_CCL) + return MATCH_FAILURE; + + if ((pdata->flags & SUPPRESS) == 0) + { + pdata->nassigned++; + if (pdata->code != CT_CHAR) + *p = 0; + } + pdata->nread += n; + return 0; +} +int +_scanf_i (struct _reent *rptr, + struct _scan_data_t *pdata, + FILE *fp, va_list *ap) +{ +#define CCFN_PARAMS _PARAMS((struct _reent *, const char *, char **, int)) + /* Conversion function (strtol/strtoul). */ + u_long (*ccfn)CCFN_PARAMS=0; + char *p; + int n; + char *xdigits = "A-Fa-f8901234567]"; + char *prefix_chars[3] = {"+-", "00", "xX"}; + + /* Scan an integer as if by strtol/strtoul. */ + unsigned width_left = 0; + int skips = 0; + + ccfn = (pdata->code == CT_INT) ? (u_long (*)CCFN_PARAMS)_strtol_r : _strtoul_r; +#ifdef hardway + if (pdata->width == 0 || pdata->width > BUF - 1) +#else + /* size_t is unsigned, hence this optimisation. */ + if (pdata->width - 1 > BUF - 2) +#endif + { + width_left = pdata->width - (BUF - 1); + pdata->width = BUF - 1; + } + p = pdata->buf; + pdata->flags |= NDIGITS | NZDIGITS | NNZDIGITS; + + /* Process [sign] [0] [xX] prefixes sequently. */ + for (n = 0; n < 3; n++) + { + if (!memchr (prefix_chars[n], *fp->_p, 2)) + continue; + + if (n == 1) + { + if (pdata->base == 0) + { + pdata->base = 8; + pdata->flags |= PFXOK; + } + pdata->flags &= ~(NZDIGITS | NDIGITS); + } + else if (n == 2) + { + if ((pdata->flags & (PFXOK | NZDIGITS)) != PFXOK) + continue; + pdata->base = 16; + + /* We must reset the NZDIGITS and NDIGITS + flags that would have been unset by seeing + the zero that preceded the X or x. + + ??? It seems unnecessary to reset the NZDIGITS. */ + pdata->flags |= NDIGITS; + } + if (pdata->width-- > 0) + { + *p++ = *fp->_p++; + fp->_r--; + if ((fp->_r <= 0 && pdata->pfn_refill (rptr, fp))) + goto match_end; + } + } + + if (pdata->base == 0) + pdata->base = 10; + + /* The check is un-necessary if xdigits points to exactly the string: + "A-Fa-f8901234567]". The code is kept only for reading's sake. */ +#if 0 + if (pdata->base != 16) +#endif + xdigits = xdigits + 16 - pdata->base; + + /* Initilize ccltab according to pdata->base. */ + __sccl (pdata->ccltab, (unsigned char *) xdigits); + for (; pdata->width; pdata->width--) + { + n = *fp->_p; + if (pdata->ccltab[n] == 0) + break; + else if (n == '0' && (pdata->flags & NNZDIGITS)) + { + ++skips; + if (width_left) + { + width_left--; + pdata->width++; + } + goto skip; + } + pdata->flags &= ~(NDIGITS | NNZDIGITS); + /* Char is legal: store it and look at the next. */ + *p++ = *fp->_p; +skip: + if (--fp->_r > 0) + fp->_p++; + else if (pdata->pfn_refill (rptr, fp)) + /* "EOF". */ + break; + } + /* If we had only a sign, it is no good; push back the sign. + If the number ends in `x', it was [sign] '0' 'x', so push back + the x and treat it as [sign] '0'. + Use of ungetc here and below assumes ASCII encoding; we are only + pushing back 7-bit characters, so casting to unsigned char is + not necessary. */ +match_end: + if (pdata->flags & NDIGITS) + { + if (p > pdata->buf) + pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+xX]". */ + + if (p == pdata->buf) + return MATCH_FAILURE; + } + if ((pdata->flags & SUPPRESS) == 0) + { + u_long ul; + *p = 0; + ul = (*ccfn) (rptr, pdata->buf, (char **) NULL, pdata->base); + if (pdata->flags & POINTER) + *GET_ARG (N, *ap, void **) = (void *) (uintptr_t) ul; + else if (pdata->flags & SHORT) + *GET_ARG (N, *ap, short *) = ul; + else if (pdata->flags & LONG) + *GET_ARG (N, *ap, long *) = ul; + else + *GET_ARG (N, *ap, int *) = ul; + + pdata->nassigned++; + } + pdata->nread += p - pdata->buf + skips; + return 0; +} + |