233 lines
6.3 KiB
C
233 lines
6.3 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|