1 /*
2  * Copyright (c) 2012-2014 ARM Ltd
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the company may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #define _DEFAULT_SOURCE
30 #include <_ansi.h>
31 #include <newlib.h>
32 #include <ctype.h>
33 #include <wctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <limits.h>
38 #include <wchar.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <errno.h>
42 #include "local.h"
43 #include "../stdlib/local.h"
44 
45 #include "nano-vfscanf_local.h"
46 
47 int
_scanf_chars(struct _scan_data_t * pdata,FILE * fp,va_list * ap)48 _scanf_chars (
49 	      struct _scan_data_t *pdata,
50 	      FILE *fp, va_list *ap)
51 {
52   int n;
53   char *p;
54 
55   if (pdata->width == 0)
56     pdata->width = (pdata->code == CT_CHAR) ? 1 : (size_t)~0;
57 
58   n = 0;
59   if ((pdata->flags & SUPPRESS) == 0)
60     p = GET_ARG (N, *ap, char *);
61 
62   /* It's impossible to have EOF when we get here.  */
63   while ((pdata->code == CT_CHAR)
64 	 || (pdata->code == CT_CCL && pdata->ccltab[*fp->_p])
65 	 || (pdata->code == CT_STRING && !isspace (*fp->_p)))
66     {
67       n++;
68       if ((pdata->flags & SUPPRESS) == 0)
69 	*p++ = *fp->_p;
70 
71       fp->_r--, fp->_p++;
72       if (--pdata->width == 0)
73 	break;
74 
75       if ((fp->_r <= 0 && pdata->pfn_refill (fp)))
76 	break;
77     }
78   /* For CT_CHAR, it is impossible to have input_failure(n == 0) here.
79      For CT_CCL, it is impossible to have input_failure here.
80      For CT_STRING, it is possible to have empty string.  */
81   if (n == 0 && pdata->code == CT_CCL)
82     return MATCH_FAILURE;
83 
84   if ((pdata->flags & SUPPRESS) == 0)
85     {
86       pdata->nassigned++;
87       if (pdata->code != CT_CHAR)
88 	*p = 0;
89     }
90   pdata->nread += n;
91   return 0;
92 }
93 int
_scanf_i(struct _scan_data_t * pdata,FILE * fp,va_list * ap)94 _scanf_i (
95 	  struct _scan_data_t *pdata,
96 	  FILE *fp, va_list *ap)
97 {
98 #define CCFN_PARAMS	(const char *, char **, int)
99   /* Conversion function (strtol/strtoul).  */
100   u_long (*ccfn)CCFN_PARAMS=0;
101   char *p;
102   int n;
103   char *xdigits = "A-Fa-f8901234567]";
104   char *prefix_chars[3] = {"+-", "00", "xX"};
105 
106   /* Scan an integer as if by strtol/strtoul.  */
107   unsigned width_left = 0;
108   int skips = 0;
109 
110   ccfn = (pdata->code == CT_INT) ? (u_long (*)CCFN_PARAMS)strtol : strtoul;
111 #ifdef hardway
112   if (pdata->width == 0 || pdata->width > BUF - 1)
113 #else
114   /* size_t is unsigned, hence this optimisation.  */
115   if (pdata->width - 1 > BUF - 2)
116 #endif
117     {
118       width_left = pdata->width - (BUF - 1);
119       pdata->width = BUF - 1;
120     }
121   p = pdata->buf;
122   pdata->flags |= NDIGITS | NZDIGITS | NNZDIGITS;
123 
124   /* Process [sign] [0] [xX] prefixes sequently.  */
125   for (n = 0; n < 3; n++)
126     {
127       if (!memchr (prefix_chars[n], *fp->_p, 2))
128 	continue;
129 
130       if (n == 1)
131 	{
132 	  if (pdata->base == 0)
133 	    {
134 	      pdata->base = 8;
135 	      pdata->flags |= PFXOK;
136 	    }
137 	  pdata->flags &= ~(NZDIGITS | NDIGITS);
138 	}
139       else if (n == 2)
140 	{
141 	  if ((pdata->flags & (PFXOK | NZDIGITS)) != PFXOK)
142 	    continue;
143 	  pdata->base = 16;
144 
145 	  /* We must reset the NZDIGITS and NDIGITS
146 	     flags that would have been unset by seeing
147 	     the zero that preceded the X or x.
148 
149 	     ??? It seems unnecessary to reset the NZDIGITS.  */
150 	  pdata->flags |= NDIGITS;
151 	}
152       if (pdata->width-- > 0)
153 	{
154 	  *p++ = *fp->_p++;
155 	  fp->_r--;
156 	  if ((fp->_r <= 0 && pdata->pfn_refill (fp)))
157 	    goto match_end;
158 	}
159     }
160 
161   if (pdata->base == 0)
162     pdata->base = 10;
163 
164   /* The check is un-necessary if xdigits points to exactly the string:
165      "A-Fa-f8901234567]".  The code is kept only for reading's sake.  */
166 #if 0
167   if (pdata->base != 16)
168 #endif
169   xdigits = xdigits + 16 - pdata->base;
170 
171   /* Initilize ccltab according to pdata->base.  */
172   __sccl (pdata->ccltab, (unsigned char *) xdigits);
173   for (; pdata->width; pdata->width--)
174     {
175       n = *fp->_p;
176       if (pdata->ccltab[n] == 0)
177 	break;
178       else if (n == '0' && (pdata->flags & NNZDIGITS))
179 	{
180 	  ++skips;
181 	  if (width_left)
182 	    {
183 	      width_left--;
184 	      pdata->width++;
185 	    }
186 	  goto skip;
187 	}
188       pdata->flags &= ~(NDIGITS | NNZDIGITS);
189       /* Char is legal: store it and look at the next.  */
190       *p++ = *fp->_p;
191 skip:
192       if (--fp->_r > 0)
193 	fp->_p++;
194       else if (pdata->pfn_refill (fp))
195 	/* "EOF".  */
196 	break;
197     }
198   /* If we had only a sign, it is no good; push back the sign.
199      If the number ends in `x', it was [sign] '0' 'x', so push back
200      the x and treat it as [sign] '0'.
201      Use of ungetc here and below assumes ASCII encoding; we are only
202      pushing back 7-bit characters, so casting to unsigned char is
203      not necessary.  */
204 match_end:
205   if (pdata->flags & NDIGITS)
206     {
207       if (p > pdata->buf)
208 	pdata->pfn_ungetc (*--p, fp); /* "[-+xX]".  */
209 
210       if (p == pdata->buf)
211 	return MATCH_FAILURE;
212     }
213   if ((pdata->flags & SUPPRESS) == 0)
214     {
215       u_long ul;
216       *p = 0;
217       ul = (*ccfn) (pdata->buf, (char **) NULL, pdata->base);
218       if (pdata->flags & POINTER)
219 	*GET_ARG (N, *ap, void **) = (void *) (uintptr_t) ul;
220       else if (pdata->flags & SHORT)
221 	*GET_ARG (N, *ap, short *) = ul;
222       else if (pdata->flags & LONG)
223 	*GET_ARG (N, *ap, long *) = ul;
224       else
225 	*GET_ARG (N, *ap, int *) = ul;
226 
227       pdata->nassigned++;
228     }
229   pdata->nread += p - pdata->buf + skips;
230   return 0;
231 }
232 
233