source: trunk/libs/newlib/src/newlib/libc/stdio/nano-vfscanf_float.c @ 620

Last change on this file since 620 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 7.9 KB
Line 
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#include <_ansi.h>
19#include <reent.h>
20#include <newlib.h>
21#include <ctype.h>
22#include <wctype.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdint.h>
26#include <limits.h>
27#include <wchar.h>
28#include <string.h>
29#include <stdarg.h>
30#include <errno.h>
31#include "local.h"
32#include "../stdlib/local.h"
33#include "nano-vfscanf_local.h"
34
35#ifdef FLOATING_POINT
36int
37_scanf_float (struct _reent *rptr,
38              struct _scan_data_t *pdata,
39              FILE *fp, va_list *ap)
40{
41  int c;
42  char *p;
43  float *flp;
44  _LONG_DOUBLE *ldp;
45
46  /* Scan a floating point number as if by strtod.  */
47  /* This code used to assume that the number of digits is reasonable.
48     However, ANSI / ISO C makes no such stipulation; we have to get
49     exact results even when there is an unreasonable amount of leading
50     zeroes.  */
51  long leading_zeroes = 0;
52  long zeroes, exp_adjust;
53  char *exp_start = NULL;
54  unsigned width_left = 0;
55  char nancount = 0;
56  char infcount = 0;
57#ifdef hardway
58  if (pdata->width == 0 || pdata->width > BUF - 1)
59#else
60  /* size_t is unsigned, hence this optimisation.  */
61  if (pdata->width - 1 > BUF - 2)
62#endif
63    {
64      width_left = pdata->width - (BUF - 1);
65      pdata->width = BUF - 1;
66    }
67  pdata->flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
68  zeroes = 0;
69  exp_adjust = 0;
70  for (p = pdata->buf; pdata->width; )
71    {
72      c = *fp->_p;
73      /* This code mimicks the integer conversion code,
74         but is much simpler.  */
75      switch (c)
76        {
77        case '0':
78          if (pdata->flags & NDIGITS)
79            {
80              pdata->flags &= ~SIGNOK;
81              zeroes++;
82              if (width_left)
83                {
84                  width_left--;
85                  pdata->width++;
86                }
87              goto fskip;
88            }
89        /* Fall through.  */
90        case '1':
91        case '2':
92        case '3':
93        case '4':
94        case '5':
95        case '6':
96        case '7':
97        case '8':
98        case '9':
99          if (nancount + infcount == 0)
100            {
101              pdata->flags &= ~(SIGNOK | NDIGITS);
102              goto fok;
103            }
104          break;
105
106        case '+':
107        case '-':
108          if (pdata->flags & SIGNOK)
109            {
110              pdata->flags &= ~SIGNOK;
111              goto fok;
112            }
113          break;
114        case 'n':
115        case 'N':
116          if (nancount == 0 && zeroes == 0
117              && (pdata->flags & (NDIGITS | DPTOK | EXPOK)) ==
118                                  (NDIGITS | DPTOK | EXPOK))
119            {
120              pdata->flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
121              nancount = 1;
122              goto fok;
123            }
124          if (nancount == 2)
125            {
126              nancount = 3;
127              goto fok;
128            }
129          if (infcount == 1 || infcount == 4)
130            {
131              infcount++;
132              goto fok;
133            }
134          break;
135        case 'a':
136        case 'A':
137          if (nancount == 1)
138            {
139              nancount = 2;
140              goto fok;
141            }
142          break;
143        case 'i':
144        case 'I':
145          if (infcount == 0 && zeroes == 0
146              && (pdata->flags & (NDIGITS | DPTOK | EXPOK)) ==
147                                  (NDIGITS | DPTOK | EXPOK))
148            {
149              pdata->flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
150              infcount = 1;
151              goto fok;
152            }
153          if (infcount == 3 || infcount == 5)
154            {
155              infcount++;
156              goto fok;
157            }
158          break;
159        case 'f':
160        case 'F':
161          if (infcount == 2)
162            {
163              infcount = 3;
164              goto fok;
165            }
166          break;
167        case 't':
168        case 'T':
169          if (infcount == 6)
170            {
171              infcount = 7;
172              goto fok;
173            }
174          break;
175        case 'y':
176        case 'Y':
177          if (infcount == 7)
178            {
179              infcount = 8;
180              goto fok;
181            }
182          break;
183        case '.':
184          if (pdata->flags & DPTOK)
185            {
186              pdata->flags &= ~(SIGNOK | DPTOK);
187              leading_zeroes = zeroes;
188              goto fok;
189            }
190          break;
191        case 'e':
192        case 'E':
193          /* No exponent without some digits.  */
194          if ((pdata->flags & (NDIGITS | EXPOK)) == EXPOK
195              || ((pdata->flags & EXPOK) && zeroes))
196            {
197              if (! (pdata->flags & DPTOK))
198                {
199                  exp_adjust = zeroes - leading_zeroes;
200                  exp_start = p;
201                }
202              pdata->flags =
203                (pdata->flags & ~(EXPOK | DPTOK)) | SIGNOK | NDIGITS;
204              zeroes = 0;
205              goto fok;
206            }
207          break;
208        }
209      break;
210fok:
211      *p++ = c;
212fskip:
213      pdata->width--;
214      ++pdata->nread;
215      if (--fp->_r > 0)
216        fp->_p++;
217      else if (pdata->pfn_refill (rptr, fp))
218        /* "EOF".  */
219        break;
220    }
221  if (zeroes)
222    pdata->flags &= ~NDIGITS;
223  /* We may have a 'N' or possibly even [sign] 'N' 'a' as the
224     start of 'NaN', only to run out of chars before it was
225     complete (or having encountered a non-matching char).  So
226     check here if we have an outstanding nancount, and if so
227     put back the chars we did swallow and treat as a failed
228     match.
229
230     FIXME - we still don't handle NAN([0xdigits]).  */
231  if (nancount - 1U < 2U)
232    {
233      /* "nancount && nancount < 3".  */
234      /* Newlib's ungetc works even if we called __srefill in
235         the middle of a partial parse, but POSIX does not
236         guarantee that in all implementations of ungetc.  */
237      while (p > pdata->buf)
238        {
239          pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+nNaA]".  */
240          --pdata->nread;
241        }
242      return MATCH_FAILURE;
243    }
244  /* Likewise for 'inf' and 'infinity'.  But be careful that
245     'infinite' consumes only 3 characters, leaving the stream
246     at the second 'i'.  */
247  if (infcount - 1U < 7U)
248    {
249      /* "infcount && infcount < 8".  */
250      if (infcount >= 3) /* valid 'inf', but short of 'infinity'.  */
251        while (infcount-- > 3)
252          {
253            pdata->pfn_ungetc (rptr, *--p, fp); /* "[iInNtT]".  */
254            --pdata->nread;
255          }
256      else
257        {
258          while (p > pdata->buf)
259            {
260              pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+iInN]".  */
261              --pdata->nread;
262            }
263          return MATCH_FAILURE;
264        }
265    }
266  /* If no digits, might be missing exponent digits
267     (just give back the exponent) or might be missing
268     regular digits, but had sign and/or decimal point.  */
269  if (pdata->flags & NDIGITS)
270    {
271      if (pdata->flags & EXPOK)
272        {
273          /* No digits at all.  */
274          while (p > pdata->buf)
275            {
276              pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+.]".  */
277              --pdata->nread;
278            }
279          return MATCH_FAILURE;
280        }
281      /* Just a bad exponent (e and maybe sign).  */
282      c = *--p;
283      --pdata->nread;
284      if (c != 'e' && c != 'E')
285        {
286          pdata->pfn_ungetc (rptr, c, fp); /* "[-+]".  */
287          c = *--p;
288          --pdata->nread;
289        }
290      pdata->pfn_ungetc (rptr, c, fp); /* "[eE]".  */
291    }
292  if ((pdata->flags & SUPPRESS) == 0)
293    {
294      double fp;
295      long new_exp = 0;
296
297      *p = 0;
298      if ((pdata->flags & (DPTOK | EXPOK)) == EXPOK)
299        {
300          exp_adjust = zeroes - leading_zeroes;
301          new_exp = -exp_adjust;
302          exp_start = p;
303        }
304      else if (exp_adjust)
305        new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
306
307      if (exp_adjust)
308        {
309          /* If there might not be enough space for the new exponent,
310             truncate some trailing digits to make room.  */
311          if (exp_start >= pdata->buf + BUF - MAX_LONG_LEN)
312            exp_start = pdata->buf + BUF - MAX_LONG_LEN - 1;
313          sprintf (exp_start, "e%ld", new_exp);
314        }
315
316      /* Current _strtold routine is markedly slower than
317         _strtod_r.  Only use it if we have a long double
318         result.  */
319      fp = _strtod_r (rptr, pdata->buf, NULL);
320
321      /* Do not support long double.  */
322      if (pdata->flags & LONG)
323        *GET_ARG (N, *ap, double *) = fp;
324      else if (pdata->flags & LONGDBL)
325        {
326          ldp = GET_ARG (N, *ap, _LONG_DOUBLE *);
327          *ldp = fp;
328        }
329      else
330        {
331          flp = GET_ARG (N, *ap, float *);
332          if (isnan (fp))
333            *flp = nanf (NULL);
334          else
335            *flp = fp;
336        }
337      pdata->nassigned++;
338    }
339  return 0;
340}
341#endif
342
Note: See TracBrowser for help on using the repository browser.