source: trunk/libs/newlib/src/newlib/libc/stdio/nano-vfscanf.c @ 567

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

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

File size: 12.3 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/*
19 * Copyright (c) 2012-2014 ARM Ltd
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. The name of the company may not be used to endorse or promote
31 *    products derived from this software without specific prior written
32 *    permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
35 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
37 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
39 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
40 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
41 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
43 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
46/*
47FUNCTION
48<<vfscanf>>, <<vscanf>>, <<vsscanf>>---format argument list
49
50INDEX
51        vfscanf
52INDEX
53        _vfscanf_r
54INDEX
55        vscanf
56INDEX
57        _vscanf_r
58INDEX
59        vsscanf
60INDEX
61        _vsscanf_r
62
63SYNOPSIS
64        #include <stdio.h>
65        #include <stdarg.h>
66        int vscanf(const char *<[fmt]>, va_list <[list]>);
67        int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
68        int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
69
70        int _vscanf_r(struct _reent *<[reent]>, const char *<[fmt]>,
71                       va_list <[list]>);
72        int _vfscanf_r(struct _reent *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
73                       va_list <[list]>);
74        int _vsscanf_r(struct _reent *<[reent]>, const char *<[str]>,
75                       const char *<[fmt]>, va_list <[list]>);
76
77DESCRIPTION
78<<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
79of <<scanf>>, <<fscanf>>, and <<sscanf>>.  They differ only in
80allowing their caller to pass the variable argument list as a
81<<va_list>> object (initialized by <<va_start>>) rather than
82directly accepting a variable number of arguments.
83
84RETURNS
85The return values are consistent with the corresponding functions:
86<<vscanf>> returns the number of input fields successfully scanned,
87converted, and stored; the return value does not include scanned
88fields which were not stored.
89
90If <<vscanf>> attempts to read at end-of-file, the return value
91is <<EOF>>.
92
93If no fields were stored, the return value is <<0>>.
94
95The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
96reentrant versions which take an additional first parameter which points to the
97reentrancy structure.
98
99PORTABILITY
100These are GNU extensions.
101
102Supporting OS subroutines required:
103*/
104
105#include <_ansi.h>
106#include <reent.h>
107#include <newlib.h>
108#include <ctype.h>
109#include <wctype.h>
110#include <stdio.h>
111#include <stdlib.h>
112#include <stdint.h>
113#include <limits.h>
114#include <wchar.h>
115#include <string.h>
116#include <stdarg.h>
117#include <errno.h>
118#include "local.h"
119#include "../stdlib/local.h"
120#include "nano-vfscanf_local.h"
121
122/* GCC PR 14577 at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557 */
123#if __STDC_VERSION__ >= 201112L
124#define va_ptr(ap) _Generic(&(ap), va_list *: &(ap), default: (va_list *)(ap))
125#elif __GNUC__ >= 4
126#define va_ptr(ap) __builtin_choose_expr(__builtin_types_compatible_p(__typeof__(&(ap)), va_list *), &(ap), (va_list *)(ap))
127#else
128#define va_ptr(ap) (sizeof(ap) == sizeof(va_list) ? (va_list *)&(ap) : (va_list *)(ap))
129#endif
130
131#define VFSCANF vfscanf
132#define _VFSCANF_R _vfscanf_r
133#define __SVFSCANF __svfscanf
134#ifdef STRING_ONLY
135#  define __SVFSCANF_R __ssvfscanf_r
136#else
137#  define __SVFSCANF_R __svfscanf_r
138#endif
139
140/* vfscanf.  */
141
142#ifndef STRING_ONLY
143
144#ifndef _REENT_ONLY
145
146int
147VFSCANF (register FILE *fp,
148       const char *fmt,
149       va_list ap)
150{
151  CHECK_INIT(_REENT, fp);
152  return __SVFSCANF_R (_REENT, fp, fmt, ap);
153}
154
155int
156vfiscanf (FILE *, const char *, __VALIST)
157       _ATTRIBUTE ((__alias__("vfscanf")));
158
159int
160__SVFSCANF (register FILE *fp,
161       char const *fmt0,
162       va_list ap)
163{
164  return __SVFSCANF_R (_REENT, fp, fmt0, ap);
165}
166
167#endif
168
169int
170_VFSCANF_R (struct _reent *data,
171       register FILE *fp,
172       const char *fmt,
173       va_list ap)
174{
175  CHECK_INIT(data, fp);
176  return __SVFSCANF_R (data, fp, fmt, ap);
177}
178
179int
180_vfiscanf_r (struct _reent *, FILE *, const char *, __VALIST)
181       _ATTRIBUTE ((__alias__("_vfscanf_r")));
182#endif /* !STRING_ONLY.  */
183
184#if defined (STRING_ONLY)
185/* When dealing with the sscanf family, we don't want to use the
186   regular ungetc which will drag in file I/O items we don't need.
187   So, we create our own trimmed-down version.  */
188int
189_sungetc_r (struct _reent *data,
190        int c,
191        register FILE *fp)
192{
193  if (c == EOF)
194    return (EOF);
195
196  /* After ungetc, we won't be at eof anymore.  */
197  fp->_flags &= ~__SEOF;
198  c = (unsigned char) c;
199
200  /* If we are in the middle of ungetc'ing, just continue.
201     This may require expanding the current ungetc buffer.  */
202
203  if (HASUB (fp))
204    {
205      if (fp->_r >= fp->_ub._size && __submore (data, fp))
206        return EOF;
207
208      *--fp->_p = c;
209      fp->_r++;
210      return c;
211    }
212
213  /* If we can handle this by simply backing up, do so,
214     but never replace the original character.
215     (This makes sscanf() work when scanning `const' data).  */
216  if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && fp->_p[-1] == c)
217    {
218      fp->_p--;
219      fp->_r++;
220      return c;
221    }
222
223  /* Create an ungetc buffer.
224     Initially, we will use the `reserve' buffer.  */
225  fp->_ur = fp->_r;
226  fp->_up = fp->_p;
227  fp->_ub._base = fp->_ubuf;
228  fp->_ub._size = sizeof (fp->_ubuf);
229  fp->_ubuf[sizeof (fp->_ubuf) - 1] = c;
230  fp->_p = &fp->_ubuf[sizeof (fp->_ubuf) - 1];
231  fp->_r = 1;
232  return c;
233}
234
235/* String only version of __srefill_r for sscanf family.  */
236int
237__ssrefill_r (struct _reent * ptr,
238       register FILE * fp)
239{
240  /* Our only hope of further input is the ungetc buffer.
241     If there is anything in that buffer to read, return.  */
242  if (HASUB (fp))
243    {
244      FREEUB (ptr, fp);
245      if ((fp->_r = fp->_ur) != 0)
246        {
247          fp->_p = fp->_up;
248          return 0;
249        }
250    }
251
252  /* Otherwise we are out of character input.  */
253  fp->_p = fp->_bf._base;
254  fp->_r = 0;
255  fp->_flags |= __SEOF;
256  return EOF;
257}
258
259#else
260int _sungetc_r (struct _reent *, int, register FILE *);
261int __ssrefill_r (struct _reent *, register FILE *);
262size_t _sfread_r (struct _reent *, void *buf, size_t, size_t, FILE *);
263#endif /* !STRING_ONLY.  */
264
265int
266__SVFSCANF_R (struct _reent *rptr,
267       register FILE *fp,
268       char const *fmt0,
269       va_list ap)
270{
271  register u_char *fmt = (u_char *) fmt0;
272  register int c;               /* Character from format, or conversion.  */
273  register char *p;             /* Points into all kinds of strings.  */
274  char ccltab[256];             /* Character class table for %[...].  */
275
276  int ret;
277  char *cp;
278
279  struct _scan_data_t scan_data;
280  int (*scan_func)(struct _reent*, struct _scan_data_t*, FILE *, va_list *);
281
282  _newlib_flockfile_start (fp);
283
284  scan_data.nassigned = 0;
285  scan_data.nread = 0;
286  scan_data.ccltab = ccltab;
287  scan_data.pfn_ungetc = _ungetc_r;
288  scan_data.pfn_refill = __srefill_r;
289
290  for (;;)
291    {
292      if (*fmt == 0)
293        goto all_done;
294
295      if (isspace (*fmt))
296        {
297          while ((fp->_r > 0 || !scan_data.pfn_refill(rptr, fp))
298                 && isspace (*fp->_p))
299            {
300              scan_data.nread++;
301              fp->_r--;
302              fp->_p++;
303            }
304          fmt++;
305          continue;
306        }
307      if ((c = *fmt++) != '%')
308        goto literal;
309
310      scan_data.width = 0;
311      scan_data.flags = 0;
312
313      if (*fmt == '*')
314        {
315          scan_data.flags |= SUPPRESS;
316          fmt++;
317        }
318
319      for (; is_digit (*fmt); fmt++)
320        scan_data.width = 10 * scan_data.width + to_digit (*fmt);
321
322      /* The length modifiers.  */
323      p = "hlL";
324      if ((cp = memchr (p, *fmt, 3)) != NULL) {
325        scan_data.flags |= (SHORT << (cp - p));
326        fmt++;
327      }
328
329      /* Switch on the format.  continue if done; break once format
330         type is derived.  */
331      c = *fmt++;
332      switch (c)
333        {
334        case '%':
335        literal:
336          if ((fp->_r <= 0 && scan_data.pfn_refill(rptr, fp)))
337            goto input_failure;
338          if (*fp->_p != c)
339            goto match_failure;
340          fp->_r--, fp->_p++;
341          scan_data.nread++;
342          continue;
343
344        case 'p':
345          scan_data.flags |= POINTER;
346        case 'x':
347        case 'X':
348          scan_data.flags |= PFXOK;
349          scan_data.base = 16;
350          goto number;
351        case 'd':
352        case 'u':
353          scan_data.base = 10;
354          goto number;
355        case 'i':
356          scan_data.base = 0;
357          goto number;
358        case 'o':
359          scan_data.base = 8;
360        number:
361          scan_data.code = (c < 'o') ? CT_INT : CT_UINT;
362          break;
363
364        case '[':
365          fmt = (u_char *) __sccl (ccltab, (unsigned char *) fmt);
366          scan_data.flags |= NOSKIP;
367          scan_data.code = CT_CCL;
368          break;
369        case 'c':
370          scan_data.flags |= NOSKIP;
371          scan_data.code = CT_CHAR;
372          break;
373        case 's':
374          scan_data.code = CT_STRING;
375          break;
376
377        case 'n':
378          if (scan_data.flags & SUPPRESS)       /* ???  */
379            continue;
380
381          if (scan_data.flags & SHORT)
382            *GET_ARG (N, ap, short *) = scan_data.nread;
383          else if (scan_data.flags & LONG)
384            *GET_ARG (N, ap, long *) = scan_data.nread;
385          else
386            *GET_ARG (N, ap, int *) = scan_data.nread;
387
388          continue;
389
390        /* Disgusting backwards compatibility hacks.    XXX.  */
391        case '\0':              /* compat.  */
392          _newlib_flockfile_exit (fp);
393          return EOF;
394
395#ifdef FLOATING_POINT
396        case 'e': case 'E':
397        case 'f': case 'F':
398        case 'g': case 'G':
399          scan_data.code = CT_FLOAT;
400          break;
401#endif
402        default:                /* compat.  */
403          scan_data.code = CT_INT;
404          scan_data.base = 10;
405          break;
406        }
407
408      /* We have a conversion that requires input.  */
409      if ((fp->_r <= 0 && scan_data.pfn_refill (rptr, fp)))
410        goto input_failure;
411
412      /* Consume leading white space, except for formats that
413         suppress this.  */
414      if ((scan_data.flags & NOSKIP) == 0)
415        {
416          while (isspace (*fp->_p))
417            {
418              scan_data.nread++;
419              if (--fp->_r > 0)
420                fp->_p++;
421              else if (scan_data.pfn_refill (rptr, fp))
422                goto input_failure;
423            }
424          /* Note that there is at least one character in the
425             buffer, so conversions that do not set NOSKIP ca
426             no longer result in an input failure.  */
427        }
428      ret = 0;
429      if (scan_data.code < CT_INT)
430        ret = _scanf_chars (rptr, &scan_data, fp, va_ptr(ap));
431      else if (scan_data.code < CT_FLOAT)
432        ret = _scanf_i (rptr, &scan_data, fp, va_ptr(ap));
433#ifdef FLOATING_POINT
434      else if (_scanf_float)
435        ret = _scanf_float (rptr, &scan_data, fp, va_ptr(ap));
436#endif
437
438      if (ret == MATCH_FAILURE)
439        goto match_failure;
440      else if (ret == INPUT_FAILURE)
441        goto input_failure;
442    }
443input_failure:
444  /* On read failure, return EOF failure regardless of matches; errno
445     should have been set prior to here.  On EOF failure (including
446     invalid format string), return EOF if no matches yet, else number
447     of matches made prior to failure.  */
448  _newlib_flockfile_exit (fp);
449  return scan_data.nassigned && !(fp->_flags & __SERR) ? scan_data.nassigned
450                                                       : EOF;
451match_failure:
452all_done:
453  /* Return number of matches, which can be 0 on match failure.  */
454  _newlib_flockfile_end (fp);
455  return scan_data.nassigned;
456}
457
458#ifdef STRING_ONLY
459int
460__ssvfiscanf_r (struct _reent *, FILE *, const char *, __VALIST)
461       _ATTRIBUTE ((__alias__("__ssvfscanf_r")));
462#else
463int
464__svfiscanf_r (struct _reent *, FILE *, const char *, __VALIST)
465       _ATTRIBUTE ((__alias__("__svfscanf_r")));
466#endif
467
Note: See TracBrowser for help on using the repository browser.