source: trunk/libs/newlib/src/newlib/libc/stdio/nano-vfprintf.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: 17.4 KB
Line 
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 2012-2014 ARM Ltd
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. The name of the company may not be used to endorse or promote
46 *    products derived from this software without specific prior written
47 *    permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
50 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
51 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
54 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
55 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
56 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
57 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 */
60
61/*
62FUNCTION
63<<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list
64
65INDEX
66        vfprintf
67INDEX
68        _vfprintf_r
69INDEX
70        vprintf
71INDEX
72        _vprintf_r
73INDEX
74        vsprintf
75INDEX
76        _vsprintf_r
77INDEX
78        vsnprintf
79INDEX
80        _vsnprintf_r
81INDEX
82        vasprintf
83INDEX
84        _vasprintf_r
85INDEX
86        vasnprintf
87INDEX
88        _vasnprintf_r
89
90SYNOPSIS
91        #include <stdio.h>
92        #include <stdarg.h>
93        int vprintf(const char *<[fmt]>, va_list <[list]>);
94        int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
95        int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
96        int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>,
97                      va_list <[list]>);
98        int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
99        char *vasnprintf(char *<[str]>, size_t *<[size]>, const char *<[fmt]>,
100                         va_list <[list]>);
101
102        int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
103                        va_list <[list]>);
104        int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
105                        const char *<[fmt]>, va_list <[list]>);
106        int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
107                        const char *<[fmt]>, va_list <[list]>);
108        int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
109                         const char *<[fmt]>, va_list <[list]>);
110        int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>,
111                         size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
112        char *_vasnprintf_r(struct _reent *<[reent]>, char *<[str]>,
113                            size_t *<[size]>, const char *<[fmt]>, va_list <[list]>);
114
115DESCRIPTION
116<<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>,
117and <<vasnprintf>> are (respectively) variants of <<printf>>,
118<<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and
119<<asnprintf>>.  They differ only in allowing their caller to pass the
120variable argument list as a <<va_list>> object (initialized by
121<<va_start>>) rather than directly accepting a variable number of
122arguments.  The caller is responsible for calling <<va_end>>.
123
124<<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>,
125<<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the
126above.
127
128RETURNS
129The return values are consistent with the corresponding functions.
130
131PORTABILITY
132ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and
133<<vsnprintf>>.  The remaining functions are newlib extensions.
134
135Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
136<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
137*/
138
139#if defined(LIBC_SCCS) && !defined(lint)
140/*static char *sccsid = "from: @(#)vfprintf.c   5.50 (Berkeley) 12/16/92";*/
141static char *rcsid = "$Id$";
142#endif /* LIBC_SCCS and not lint */
143
144/* Actual printf innards.
145   This code is large and complicated...  */
146#include <newlib.h>
147
148#define VFPRINTF vfprintf
149#ifdef STRING_ONLY
150# define _VFPRINTF_R _svfprintf_r
151#else
152# define _VFPRINTF_R _vfprintf_r
153#endif
154
155#include <_ansi.h>
156#include <reent.h>
157#include <stdio.h>
158#include <stdlib.h>
159#include <string.h>
160#include <limits.h>
161#include <stdint.h>
162#include <wchar.h>
163#include <sys/lock.h>
164#include <stdarg.h>
165#include "local.h"
166#include "../stdlib/local.h"
167#include "fvwrite.h"
168#include "vfieeefp.h"
169#include "nano-vfprintf_local.h"
170
171
172/* GCC PR 14577 at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557 */
173#if __STDC_VERSION__ >= 201112L
174#define va_ptr(ap) _Generic(&(ap), va_list *: &(ap), default: (va_list *)(ap))
175#elif __GNUC__ >= 4
176#define va_ptr(ap) __builtin_choose_expr(__builtin_types_compatible_p(__typeof__(&(ap)), va_list *), &(ap), (va_list *)(ap))
177#else
178#define va_ptr(ap) (sizeof(ap) == sizeof(va_list) ? (va_list *)&(ap) : (va_list *)(ap))
179#endif
180
181/* The __ssputs_r function is shared between all versions of vfprintf
182   and vfwprintf.  */
183#ifdef STRING_ONLY
184int
185__ssputs_r (struct _reent *ptr,
186       FILE *fp,
187       const char *buf,
188       size_t len)
189{
190  register int w;
191
192  w = fp->_w;
193  if (len >= w && fp->_flags & (__SMBF | __SOPT))
194    {
195      /* Must be asprintf family.  */
196      unsigned char *str;
197      int curpos = (fp->_p - fp->_bf._base);
198      /* Choose a geometric growth factor to avoid
199       * quadratic realloc behavior, but use a rate less
200       * than (1+sqrt(5))/2 to accomodate malloc
201       * overhead. asprintf EXPECTS us to overallocate, so
202       * that it can add a trailing \0 without
203       * reallocating.  The new allocation should thus be
204       * max(prev_size*1.5, curpos+len+1).  */
205      int newsize = fp->_bf._size * 3 / 2;
206      if (newsize < curpos + len + 1)
207        newsize = curpos + len + 1;
208      if (fp->_flags & __SOPT)
209        {
210          /* asnprintf leaves original buffer alone.  */
211          str = (unsigned char *)_malloc_r (ptr, newsize);
212          if (!str)
213            {
214              ptr->_errno = ENOMEM;
215              goto err;
216            }
217          memcpy (str, fp->_bf._base, curpos);
218          fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
219        }
220      else
221        {
222          str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, newsize);
223          if (!str)
224            {
225              /* Free unneeded buffer.  */
226              _free_r (ptr, fp->_bf._base);
227              /* Ensure correct errno, even if free changed it.  */
228              ptr->_errno = ENOMEM;
229              goto err;
230            }
231        }
232      fp->_bf._base = str;
233      fp->_p = str + curpos;
234      fp->_bf._size = newsize;
235      w = len;
236      fp->_w = newsize - curpos;
237    }
238  if (len < w)
239    w = len;
240
241  (void)memmove ((void *) fp->_p, (void *) buf, (size_t) (w));
242  fp->_w -= w;
243  fp->_p += w;
244  return 0;
245
246err:
247  fp->_flags |= __SERR;
248  return EOF;
249}
250/* __ssprint_r is the original implementation of __SPRINT.  In nano
251   version formatted IO it is reimplemented as __ssputs_r for non-wide
252   char output, but __ssprint_r cannot be discarded because it is used
253   by a serial of functions like svfwprintf for wide char output.  */
254int
255__ssprint_r (struct _reent *ptr,
256       FILE *fp,
257       register struct __suio *uio)
258{
259  register size_t len;
260  register int w;
261  register struct __siov *iov;
262  register const char *p = NULL;
263
264  iov = uio->uio_iov;
265  len = 0;
266
267  if (uio->uio_resid == 0)
268    {
269      uio->uio_iovcnt = 0;
270      return (0);
271    }
272
273  do
274    {
275      while (len == 0)
276        {
277          p = iov->iov_base;
278          len = iov->iov_len;
279          iov++;
280        }
281      w = fp->_w;
282      if (len >= w && fp->_flags & (__SMBF | __SOPT))
283        {
284          /* Must be asprintf family.  */
285          unsigned char *str;
286          int curpos = (fp->_p - fp->_bf._base);
287          /* Choose a geometric growth factor to avoid
288           * quadratic realloc behavior, but use a rate less
289           * than (1+sqrt(5))/2 to accomodate malloc
290           * overhead. asprintf EXPECTS us to overallocate, so
291           * that it can add a trailing \0 without
292           * reallocating.  The new allocation should thus be
293           * max(prev_size*1.5, curpos+len+1).  */
294          int newsize = fp->_bf._size * 3 / 2;
295          if (newsize < curpos + len + 1)
296            newsize = curpos + len + 1;
297
298          if (fp->_flags & __SOPT)
299            {
300              /* asnprintf leaves original buffer alone.  */
301              str = (unsigned char *)_malloc_r (ptr, newsize);
302              if (!str)
303                {
304                  ptr->_errno = ENOMEM;
305                  goto err;
306                }
307              memcpy (str, fp->_bf._base, curpos);
308              fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
309            }
310          else
311            {
312              str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
313                                                 newsize);
314              if (!str)
315                {
316                  /* Free unneeded buffer.  */
317                  _free_r (ptr, fp->_bf._base);
318                  /* Ensure correct errno, even if free changed it.  */
319                  ptr->_errno = ENOMEM;
320                  goto err;
321                }
322            }
323          fp->_bf._base = str;
324          fp->_p = str + curpos;
325          fp->_bf._size = newsize;
326          w = len;
327          fp->_w = newsize - curpos;
328        }
329      if (len < w)
330        w = len;
331
332      (void)memmove ((void *) fp->_p, (void *) p, (size_t) (w));
333      fp->_w -= w;
334      fp->_p += w;
335      /* Pretend we copied all.  */
336      w = len;
337      p += w;
338      len -= w;
339    }
340  while ((uio->uio_resid -= w) != 0);
341
342  uio->uio_resid = 0;
343  uio->uio_iovcnt = 0;
344  return 0;
345
346err:
347  fp->_flags |= __SERR;
348  uio->uio_resid = 0;
349  uio->uio_iovcnt = 0;
350  return EOF;
351}
352#else
353/* As __ssputs_r, __sprint_r is used by output functions for wide char,
354   like vfwprint.  */
355/* Flush out all the vectors defined by the given uio,
356   then reset it so that it can be reused.  */
357int
358__sprint_r (struct _reent *ptr,
359       FILE *fp,
360       register struct __suio *uio)
361{
362  register int err = 0;
363
364  if (uio->uio_resid == 0)
365    {
366      uio->uio_iovcnt = 0;
367      return 0;
368    }
369#ifdef _WIDE_ORIENT
370    if (fp->_flags2 & __SWID)
371      {
372        struct __siov *iov;
373        wchar_t *p;
374        int i, len;
375
376        iov = uio->uio_iov;
377        for (; uio->uio_resid != 0;
378             uio->uio_resid -= len * sizeof (wchar_t), iov++)
379          {
380            p = (wchar_t *) iov->iov_base;
381            len = iov->iov_len / sizeof (wchar_t);
382            for (i = 0; i < len; i++)
383              {
384                if (_fputwc_r (ptr, p[i], fp) == WEOF)
385                  {
386                    err = -1;
387                    goto out;
388                  }
389              }
390          }
391        }
392      else
393#endif
394        err = __sfvwrite_r(ptr, fp, uio);
395out:
396  uio->uio_resid = 0;
397  uio->uio_iovcnt = 0;
398  return err;
399}
400
401_NOINLINE_STATIC int
402__sfputc_r (struct _reent *ptr,
403       int c,
404       FILE *fp)
405{
406  if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && (char)c != '\n'))
407    return (*fp->_p++ = c);
408  else
409    return (__swbuf_r(ptr, c, fp));
410}
411
412int
413__sfputs_r (struct _reent *ptr,
414       FILE *fp,
415       const char *buf,
416       size_t len)
417{
418  register int i;
419
420#ifdef _WIDE_ORIENT
421  if (fp->_flags2 & __SWID)
422    {
423      wchar_t *p;
424
425      p = (wchar_t *) buf;
426      for (i = 0; i < (len / sizeof (wchar_t)); i++)
427        {
428          if (_fputwc_r (ptr, p[i], fp) == WEOF)
429            return -1;
430        }
431    }
432  else
433#endif
434    {
435      for (i = 0; i < len; i++)
436        {
437          /* Call __sfputc_r to skip _fputc_r.  */
438          if (__sfputc_r (ptr, (int)buf[i], fp) == EOF)
439            return -1;
440        }
441    }
442  return (0);
443}
444#endif /* STRING_ONLY.  */
445
446int _VFPRINTF_R (struct _reent *, FILE *, const char *, va_list);
447
448#ifndef STRING_ONLY
449int
450VFPRINTF (FILE * fp,
451       const char *fmt0,
452       va_list ap)
453{
454  int result;
455  result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
456  return result;
457}
458
459int
460vfiprintf (FILE *, const char *, __VALIST)
461       _ATTRIBUTE ((__alias__("vfprintf")));
462#endif
463
464#ifdef STRING_ONLY
465# define __SPRINT __ssputs_r
466#else
467# define __SPRINT __sfputs_r
468#endif
469
470/* Do not need FLUSH for all sprintf functions.  */
471#ifdef STRING_ONLY
472# define FLUSH()
473#else
474# define FLUSH()
475#endif
476
477int
478_VFPRINTF_R (struct _reent *data,
479       FILE * fp,
480       const char *fmt0,
481       va_list ap)
482{
483  register char *fmt;   /* Format string.  */
484  register int n, m;    /* Handy integers (short term usage).  */
485  register char *cp;    /* Handy char pointer (short term usage).  */
486  const char *flag_chars;
487  struct _prt_data_t prt_data;  /* All data for decoding format string.  */
488
489  /* Output function pointer.  */
490  int (*pfunc)(struct _reent *, FILE *, const char *, size_t len);
491
492  pfunc = __SPRINT;
493
494#ifndef STRING_ONLY
495  /* Initialize std streams if not dealing with sprintf family.  */
496  CHECK_INIT (data, fp);
497  _newlib_flockfile_start (fp);
498
499  /* Sorry, fprintf(read_only_file, "") returns EOF, not 0.  */
500  if (cantwrite (data, fp))
501    {
502      _newlib_flockfile_exit (fp);
503      return (EOF);
504    }
505
506#else
507  /* Create initial buffer if we are called by asprintf family.  */
508  if (fp->_flags & __SMBF && !fp->_bf._base)
509    {
510      fp->_bf._base = fp->_p = _malloc_r (data, 64);
511      if (!fp->_p)
512        {
513          data->_errno = ENOMEM;
514          return EOF;
515        }
516      fp->_bf._size = 64;
517    }
518#endif
519
520  fmt = (char *)fmt0;
521  prt_data.ret = 0;
522  prt_data.blank = ' ';
523  prt_data.zero = '0';
524
525  /* Scan the format for conversions (`%' character).  */
526  for (;;)
527    {
528      cp = fmt;
529      while (*fmt != '\0' && *fmt != '%')
530        fmt += 1;
531
532      if ((m = fmt - cp) != 0)
533        {
534          PRINT (cp, m);
535          prt_data.ret += m;
536        }
537      if (*fmt == '\0')
538        goto done;
539
540      fmt++;            /* Skip over '%'.  */
541
542      prt_data.flags = 0;
543      prt_data.width = 0;
544      prt_data.prec = -1;
545      prt_data.dprec = 0;
546      prt_data.l_buf[0] = '\0';
547#ifdef FLOATING_POINT
548      prt_data.lead = 0;
549#endif
550      /* The flags.  */
551      /*
552       * ``Note that 0 is taken as a flag, not as the
553       * beginning of a field width.''
554       *        -- ANSI X3J11
555       */
556      flag_chars = "#-0+ ";
557      for (; cp = memchr (flag_chars, *fmt, 5); fmt++)
558        prt_data.flags |= (1 << (cp - flag_chars));
559
560      if (prt_data.flags & SPACESGN)
561        prt_data.l_buf[0] = ' ';
562
563      /*
564       * ``If the space and + flags both appear, the space
565       * flag will be ignored.''
566       *        -- ANSI X3J11
567       */
568      if (prt_data.flags & PLUSSGN)
569        prt_data.l_buf[0] = '+';
570
571      /* The width.  */
572      if (*fmt == '*')
573        {
574          /*
575           * ``A negative field width argument is taken as a
576           * - flag followed by a positive field width.''
577           *    -- ANSI X3J11
578           * They don't exclude field widths read from args.
579           */
580          prt_data.width = GET_ARG (n, ap, int);
581          if (prt_data.width < 0)
582            {
583              prt_data.width = -prt_data.width;
584              prt_data.flags |= LADJUST;
585            }
586          fmt++;
587        }
588      else
589        {
590          for (; is_digit (*fmt); fmt++)
591            prt_data.width = 10 * prt_data.width + to_digit (*fmt);
592        }
593
594      /* The precision.  */
595      if (*fmt == '.')
596        {
597          fmt++;
598          if (*fmt == '*')
599            {
600              fmt++;
601              prt_data.prec = GET_ARG (n, ap, int);
602              if (prt_data.prec < 0)
603                prt_data.prec = -1;
604            }
605          else
606            {
607              prt_data.prec = 0;
608              for (; is_digit (*fmt); fmt++)
609                prt_data.prec = 10 * prt_data.prec + to_digit (*fmt);
610            }
611        }
612
613      /* The length modifiers.  */
614      flag_chars = "hlL";
615      if ((cp = memchr (flag_chars, *fmt, 3)) != NULL)
616        {
617          prt_data.flags |= (SHORTINT << (cp - flag_chars));
618          fmt++;
619        }
620
621      /* The conversion specifiers.  */
622      prt_data.code = *fmt++;
623      cp = memchr ("efgEFG", prt_data.code, 6);
624#ifdef FLOATING_POINT
625      /* If cp is not NULL, we are facing FLOATING POINT NUMBER.  */
626      if (cp)
627        {
628          /* Consume floating point argument if _printf_float is not
629             linked.  */
630          if (_printf_float == NULL)
631            {
632              if (prt_data.flags & LONGDBL)
633                GET_ARG (N, ap, _LONG_DOUBLE);
634              else
635                GET_ARG (N, ap, double);
636            }
637          else
638            {
639              n = _printf_float (data, &prt_data, fp, pfunc, va_ptr(ap));
640            }
641        }
642      else
643#endif
644        n = _printf_i (data, &prt_data, fp, pfunc, va_ptr(ap));
645
646      if (n == -1)
647        goto error;
648
649      prt_data.ret += n;
650    }
651done:
652  FLUSH ();
653error:
654#ifndef STRING_ONLY
655  _newlib_flockfile_end (fp);
656#endif
657  return (__sferror (fp) ? EOF : prt_data.ret);
658}
659
660#ifdef STRING_ONLY
661int
662_svfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
663       _ATTRIBUTE ((__alias__("_svfprintf_r")));
664#else
665int
666_vfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
667       _ATTRIBUTE ((__alias__("_vfprintf_r")));
668#endif
Note: See TracBrowser for help on using the repository browser.