implement asnprintf

Jeff Johnston jjohnstn@redhat.com
Tue Apr 24 19:08:00 GMT 2007


Eric,

  A number of issues regarding ELIX_LEVEL.  These new functions should 
be level 4.  That means you need a new set of ELIX_4_SOURCES and you 
simply verify that the level is not 1, 2, or 3.  Add ELIX_4_SOURCES to 
the list of sources below.  Very straightforward.

  This patch has revealed an error I hadn't spotted before.  The dprintf 
family cannot refer to a higher level ELIX function so they must be put 
into the LEVEL 2 sources with asprintf, etc..

  Finally, the dprintf changes you have made need to either be left out 
or you need to fork the code based on the ELIX level and call the new 
LEVEL 4 functions when the _ELIX_LEVEL flag is undefined or >3.

-- Jeff J.

Eric Blake wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Consider what it takes to do formatted printing of on an arbitrary amount
> of data into a buffer.  sprintf alone is inadequate - it is too easy to
> overflow the buffer.  snprintf can be used, called first with size 0 to
> determine the length that would be printed, followed by malloc, then
> s[n]printf to do the printing, but that is needlessly processor intensive
> to traverse the arguments twice (and poor on cache behavior if the string
> exceeds cache limits).  asprintf can be used, so that only a single pass
> through the arguments is required, but that always mallocs, which is a
> potential slowdown in the common case of short output.  Therefore, it
> would be nice to have an interface that can do formatting in a single pass
> of the arguments, but which only calls malloc if the initial buffer size
> is inadequate.
>
> Enter asnprintf, a relatively new interface [1] already in use by several
> GNU programs (via gnulib [2]).  asnprintf is not a standardized interface,
> however, I think it is worth including it in newlib.  I also modified
> dprintf to take advantage of the benefits of asnprintf.
>
> [1] http://lists.gnu.org/archive/html/bug-gnulib/2007-03/msg00211.html
> [2]
> http://cvs.savannah.gnu.org/viewcvs/gnulib/lib/vasnprintf.h?rev=1.6&root=gnulib&view=markup
>
> asnprintf also has the potential advantage that, since it does not return
> an int, it could technically produce strings larger than INT_MAX in length
> (particularly on platforms where size_t is 64 bits but int is 32), unlike
> {s,as,sn}printf.  However, this particular implementation cannot do that,
> since it would be an incompatible ABI change to struct FILE to support
> 64-bit offsets reliably.
>
> OK to apply this patch?
>
> 2007-04-20  Eric Blake  <ebb9@byu.net>
>
> 	* libc/stdio/fvwrite.c (__sfvwrite_r): Handle asnprintf.
> 	* libc/stdio/asniprintf.c (asniprintf, _asniprintf_r): New file.
> 	* libc/stdio/asnprintf.c (asnprintf, _asnprintf_r): New file.
> 	* libc/stdio/vasniprintf.c (vasniprintf, _vasniprintf_r): New
> 	file.
> 	* libc/stdio/vasnprintf.c (vasnprintf, _vasnprintf_r): New file.
> 	* libc/stdio/vdprintf.c (_vdprintf_r): Rewrite to avoid malloc in
> 	typical case.
> 	* libc/stdio/vdiprintf.c (_vdiprintf_r): Likewise.
> 	* libc/stdio/Makefile.am (ELIX_SOURCES): Build new files.
> 	* libc/include/stdio.h: Add prototypes for new functions; sort
> 	existing functions.
>
> - --
> Don't work too hard, make some time for fun as well!
>
> Eric Blake             ebb9@byu.net
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.5 (Cygwin)
> Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFGKRBF84KuGfSFAYARAjBFAJ9P4k79iFTS8HqGP6VipTrySCBz3wCgtfFR
> oDZouOj3D2LE37jVhYJX79c=
> =ODwh
> -----END PGP SIGNATURE-----
>   
> ------------------------------------------------------------------------
>
> Index: libc/include/stdio.h
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/include/stdio.h,v
> retrieving revision 1.44
> diff -u -p -r1.44 stdio.h
> --- libc/include/stdio.h	10 Apr 2007 12:49:18 -0000	1.44
> +++ libc/include/stdio.h	20 Apr 2007 15:00:36 -0000
> @@ -238,6 +238,10 @@ off_t	_EXFUN(ftello, ( FILE *));
>  #ifndef _REENT_ONLY
>  int	_EXFUN(asiprintf, (char **, const char *, ...)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
> +char *	_EXFUN(asniprintf, (char *, size_t *, const char *, ...)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
> +char *	_EXFUN(asnprintf, (char *, size_t *, const char *, ...)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
>  int	_EXFUN(asprintf, (char **, const char *, ...)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
>  #ifndef dprintf
> @@ -266,16 +270,16 @@ int	_EXFUN(sniprintf, (char *, size_t, c
>  char *	_EXFUN(tempnam, (const char *, const char *));
>  int	_EXFUN(vasiprintf, (char **, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
> +char *	_EXFUN(vasniprintf, (char *, size_t *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +char *	_EXFUN(vasnprintf, (char *, size_t *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(vasprintf, (char **, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
>  int	_EXFUN(vdiprintf, (int, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
>  int	_EXFUN(vdprintf, (int, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
> -int	_EXFUN(vsniprintf, (char *, size_t, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> -int	_EXFUN(vsnprintf, (char *, size_t, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(vfiprintf, (FILE *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
>  int	_EXFUN(vfiscanf, (FILE *, const char *, __VALIST)
> @@ -284,18 +288,22 @@ int	_EXFUN(vfscanf, (FILE *, const char 
>                 _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
>  int	_EXFUN(viprintf, (const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 1, 0))));
> -int	_EXFUN(vsiprintf, (char *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
>  int	_EXFUN(viscanf, (const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__scanf__, 1, 0))));
>  int	_EXFUN(vscanf, (const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__scanf__, 1, 0))));
> +int	_EXFUN(vsiprintf, (char *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
>  int	_EXFUN(vsiscanf, (const char *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
> +int	_EXFUN(vsniprintf, (char *, size_t, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +int	_EXFUN(vsnprintf, (char *, size_t, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(vsscanf, (const char *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
> -#endif
> -#endif
> +#endif /* !_REENT_ONLY */
> +#endif /* !__STRICT_ANSI__ */
>  
>  /*
>   * Routines in POSIX 1003.1.
> @@ -319,7 +327,7 @@ int	_EXFUN(ftrylockfile, (FILE *));
>  void	_EXFUN(funlockfile, (FILE *));
>  int	_EXFUN(putc_unlocked, (int, FILE *));
>  int	_EXFUN(putchar_unlocked, (int));
> -#endif
> +#endif /* ! __STRICT_ANSI__ */
>  
>  /*
>   * Recursive versions of the above.
> @@ -327,6 +335,10 @@ int	_EXFUN(putchar_unlocked, (int));
>  
>  int	_EXFUN(_asiprintf_r, (struct _reent *, char **, const char *, ...)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
> +char *	_EXFUN(_asniprintf_r, (struct _reent *, char *, size_t *, const char *, ...)
> +               _ATTRIBUTE ((__format__ (__printf__, 4, 5))));
> +char *	_EXFUN(_asnprintf_r, (struct _reent *, char *, size_t *, const char *, ...)
> +               _ATTRIBUTE ((__format__ (__printf__, 4, 5))));
>  int	_EXFUN(_asprintf_r, (struct _reent *, char **, const char *, ...)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
>  int	_EXFUN(_diprintf_r, (struct _reent *, int, const char *, ...)
> @@ -394,6 +406,10 @@ char *	_EXFUN(_tmpnam_r, (struct _reent 
>  int	_EXFUN(_ungetc_r, (struct _reent *, int, FILE *));
>  int	_EXFUN(_vasiprintf_r, (struct _reent *, char **, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +char *	_EXFUN(_vasniprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 4, 0))));
> +char *	_EXFUN(_vasnprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 4, 0))));
>  int	_EXFUN(_vasprintf_r, (struct _reent *, char **, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(_vdiprintf_r, (struct _reent *, int, const char *, __VALIST)
> @@ -402,32 +418,32 @@ int	_EXFUN(_vdprintf_r, (struct _reent *
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(_vfiprintf_r, (struct _reent *, FILE *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +int	_EXFUN(_vfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
>  int	_EXFUN(_vfprintf_r, (struct _reent *, FILE *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +int	_EXFUN(_vfscanf_r, (struct _reent *, FILE *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
>  int	_EXFUN(_viprintf_r, (struct _reent *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
> +int	_EXFUN(_viscanf_r, (struct _reent *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
>  int	_EXFUN(_vprintf_r, (struct _reent *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
> +int	_EXFUN(_vscanf_r, (struct _reent *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
>  int	_EXFUN(_vsiprintf_r, (struct _reent *, char *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> -int	_EXFUN(_vsprintf_r, (struct _reent *, char *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
> +int	_EXFUN(_vsiscanf_r, (struct _reent *, const char *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
>  int	_EXFUN(_vsniprintf_r, (struct _reent *, char *, size_t, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 4, 0))));
>  int	_EXFUN(_vsnprintf_r, (struct _reent *, char *, size_t, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__printf__, 4, 0))));
> -int	_EXFUN(_vfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
> -int	_EXFUN(_vfscanf_r, (struct _reent *, FILE *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
> -int	_EXFUN(_viscanf_r, (struct _reent *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
> -int	_EXFUN(_vscanf_r, (struct _reent *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
> +int	_EXFUN(_vsprintf_r, (struct _reent *, char *, const char *, __VALIST)
> +               _ATTRIBUTE ((__format__ (__printf__, 3, 0))));
>  int	_EXFUN(_vsscanf_r, (struct _reent *, const char *, const char *, __VALIST)
>                 _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
> -int	_EXFUN(_vsiscanf_r, (struct _reent *, const char *, const char *, __VALIST)
> -               _ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
>  
>  ssize_t _EXFUN(__getdelim, (char **, size_t *, int, FILE *));
>  ssize_t _EXFUN(__getline, (char **, size_t *, FILE *));
> Index: libc/stdio/Makefile.am
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/Makefile.am,v
> retrieving revision 1.23
> diff -u -p -r1.23 Makefile.am
> --- libc/stdio/Makefile.am	4 Apr 2007 18:32:49 -0000	1.23
> +++ libc/stdio/Makefile.am	20 Apr 2007 15:00:36 -0000
> @@ -93,6 +93,8 @@ ELIX_SOURCES =
>  else
>  ELIX_SOURCES = \
>  	asiprintf.c		\
> +	asniprintf.c		\
> +	asnprintf.c		\
>  	asprintf.c		\
>  	fcloseall.c		\
>  	fseeko.c 		\
> @@ -101,6 +103,8 @@ ELIX_SOURCES = \
>  	mktemp.c 		\
>  	putw.c 			\
>  	vasiprintf.c		\
> +	vasniprintf.c		\
> +	vasnprintf.c		\
>  	vasprintf.c
>  endif
>  
> Index: libc/stdio/asniprintf.c
> ===================================================================
> RCS file: libc/stdio/asniprintf.c
> diff -N libc/stdio/asniprintf.c
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ libc/stdio/asniprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -0,0 +1,104 @@
> +/* Copyright 2007 Eric Blake
> + * Permission to use, copy, modify, and distribute this software
> + * is freely granted, provided that this notice is preserved.
> + */
> +/* This code was derived from asprintf.c */
> +
> +#include <_ansi.h>
> +#include <reent.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <limits.h>
> +#include <errno.h>
> +
> +char *
> +_DEFUN(_asniprintf_r, (ptr, buf, lenp, fmt),
> +       struct _reent *ptr _AND
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _DOTS)
> +{
> +  int ret;
> +  va_list ap;
> +  FILE f;
> +  size_t len = *lenp;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  va_start (ap, fmt);
> +  ret = _vfiprintf_r (ptr, &f, fmt, ap);
> +  va_end (ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#ifndef _REENT_ONLY
> +
> +char *
> +_DEFUN(asniprintf, (buf, lenp, fmt),
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _DOTS)
> +{
> +  int ret;
> +  va_list ap;
> +  FILE f;
> +  size_t len = *lenp;
> +  struct _reent *ptr = _REENT;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  va_start (ap, fmt);
> +  ret = _vfiprintf_r (ptr, &f, fmt, ap);
> +  va_end (ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#endif /* ! _REENT_ONLY */
> Index: libc/stdio/asnprintf.c
> ===================================================================
> RCS file: libc/stdio/asnprintf.c
> diff -N libc/stdio/asnprintf.c
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ libc/stdio/asnprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -0,0 +1,104 @@
> +/* Copyright 2007 Eric Blake
> + * Permission to use, copy, modify, and distribute this software
> + * is freely granted, provided that this notice is preserved.
> + */
> +/* This code was derived from asprintf.c */
> +
> +#include <_ansi.h>
> +#include <reent.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <limits.h>
> +#include <errno.h>
> +
> +char *
> +_DEFUN(_asnprintf_r, (ptr, buf, lenp, fmt),
> +       struct _reent *ptr _AND
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _DOTS)
> +{
> +  int ret;
> +  va_list ap;
> +  FILE f;
> +  size_t len = *lenp;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  va_start (ap, fmt);
> +  ret = _vfprintf_r (ptr, &f, fmt, ap);
> +  va_end (ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#ifndef _REENT_ONLY
> +
> +char *
> +_DEFUN(asnprintf, (buf, lenp, fmt),
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _DOTS)
> +{
> +  int ret;
> +  va_list ap;
> +  FILE f;
> +  size_t len = *lenp;
> +  struct _reent *ptr = _REENT;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  va_start (ap, fmt);
> +  ret = _vfprintf_r (ptr, &f, fmt, ap);
> +  va_end (ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#endif /* ! _REENT_ONLY */
> Index: libc/stdio/fvwrite.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/fvwrite.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 fvwrite.c
> --- libc/stdio/fvwrite.c	15 Mar 2007 18:40:48 -0000	1.11
> +++ libc/stdio/fvwrite.c	20 Apr 2007 15:00:37 -0000
> @@ -127,7 +127,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
>  	  w = fp->_w;
>  	  if (fp->_flags & __SSTR)
>  	    {
> -	      if (len >= w && fp->_flags & __SMBF)
> +	      if (len >= w && fp->_flags & (__SMBF | __SOPT))
>  		{ /* must be asprintf family */
>  		  unsigned char *str;
>  		  int curpos = (fp->_p - fp->_bf._base);
> @@ -141,15 +141,30 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
>  		  int newsize = fp->_bf._size * 3 / 2;
>  		  if (newsize < curpos + len + 1)
>  		    newsize = curpos + len + 1;
> -		  str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
> -						     newsize);
> -		  if (!str)
> +		  if (fp->_flags & __SOPT)
>  		    {
> -		      /* Free buffer which is no longer used.  */
> -		      _free_r (ptr, fp->_bf._base);
> -                      /* Ensure correct errno, even if free changed it.  */
> -                      ptr->_errno = ENOMEM;
> -		      goto err;
> +		      /* asnprintf leaves original buffer alone.  */
> +		      str = (unsigned char *)_malloc_r (ptr, newsize);
> +		      if (!str)
> +			{
> +			  ptr->_errno = ENOMEM;
> +			  goto err;
> +			}
> +		      memcpy (str, fp->_bf._base, curpos);
> +		      fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
> +		    }
> +		  else
> +		    {
> +		      str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
> +							 newsize);
> +		      if (!str)
> +			{
> +			  /* Free buffer which is no longer used.  */
> +			  _free_r (ptr, fp->_bf._base);
> +			  /* Ensure correct errno, even if free changed it.  */
> +			  ptr->_errno = ENOMEM;
> +			  goto err;
> +			}
>  		    }
>  		  fp->_bf._base = str;
>  		  fp->_p = str + curpos;
> Index: libc/stdio/vasniprintf.c
> ===================================================================
> RCS file: libc/stdio/vasniprintf.c
> diff -N libc/stdio/vasniprintf.c
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ libc/stdio/vasniprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -0,0 +1,68 @@
> +/* Copyright 2007 Eric Blake
> + * Permission to use, copy, modify, and distribute this software
> + * is freely granted, provided that this notice is preserved.
> + */
> +/* This code was derived from asprintf.c */
> +
> +#include <_ansi.h>
> +#include <reent.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <limits.h>
> +#include <errno.h>
> +
> +char *
> +_DEFUN(_vasniprintf_r, (ptr, buf, lenp, fmt, ap),
> +       struct _reent *ptr _AND
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _AND
> +       va_list ap)
> +{
> +  int ret;
> +  FILE f;
> +  size_t len = *lenp;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  ret = _vfiprintf_r (ptr, &f, fmt, ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#ifndef _REENT_ONLY
> +
> +char *
> +_DEFUN(vasniprintf, (buf, lenp, fmt, ap),
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _AND
> +       va_list ap)
> +{
> +  return _vasniprintf_r (_REENT, buf, lenp, fmt, ap);
> +}
> +
> +#endif /* ! _REENT_ONLY */
> Index: libc/stdio/vasnprintf.c
> ===================================================================
> RCS file: libc/stdio/vasnprintf.c
> diff -N libc/stdio/vasnprintf.c
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ libc/stdio/vasnprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -0,0 +1,68 @@
> +/* Copyright 2007 Eric Blake
> + * Permission to use, copy, modify, and distribute this software
> + * is freely granted, provided that this notice is preserved.
> + */
> +/* This code was derived from asprintf.c */
> +
> +#include <_ansi.h>
> +#include <reent.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <limits.h>
> +#include <errno.h>
> +
> +char *
> +_DEFUN(_vasnprintf_r, (ptr, buf, lenp, fmt, ap),
> +       struct _reent *ptr _AND
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _AND
> +       va_list ap)
> +{
> +  int ret;
> +  FILE f;
> +  size_t len = *lenp;
> +
> +  if (buf && len)
> +    {
> +      /* mark an existing buffer, but allow allocation of larger string */
> +      f._flags = __SWR | __SSTR | __SOPT;
> +    }
> +  else
> +    {
> +      /* mark a zero-length reallocatable buffer */
> +      f._flags = __SWR | __SSTR | __SMBF;
> +      len = 0;
> +    }
> +  f._bf._base = f._p = (unsigned char *) buf;
> +  /* For now, inherit the 32-bit signed limit of FILE._bf._size.
> +     FIXME - it would be nice to rewrite sys/reent.h to support size_t
> +     for _size.  */
> +  if (len > INT_MAX)
> +    {
> +      ptr->_errno = EOVERFLOW;
> +      return NULL;
> +    }
> +  f._bf._size = f._w = len;
> +  f._file = -1;  /* No file. */
> +  ret = _vfprintf_r (ptr, &f, fmt, ap);
> +  if (ret < 0)
> +    return NULL;
> +  *lenp = ret;
> +  *f._p = '\0';
> +  return (char *) f._bf._base;
> +}
> +
> +#ifndef _REENT_ONLY
> +
> +char *
> +_DEFUN(vasnprintf, (buf, lenp, fmt, ap),
> +       char *buf _AND
> +       size_t *lenp _AND
> +       const char *fmt _AND
> +       va_list ap)
> +{
> +  return _vasnprintf_r (_REENT, buf, lenp, fmt, ap);
> +}
> +
> +#endif /* ! _REENT_ONLY */
> Index: libc/stdio/vdiprintf.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/vdiprintf.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 vdiprintf.c
> --- libc/stdio/vdiprintf.c	4 Apr 2007 18:32:49 -0000	1.1
> +++ libc/stdio/vdiprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -18,13 +18,16 @@ _DEFUN(_vdiprintf_r, (ptr, fd, format, a
>         va_list ap)
>  {
>    char *p;
> -  int n;
> +  char buf[512];
> +  size_t n = sizeof buf;
>  
>    _REENT_SMALL_CHECK_INIT (ptr);
> -  n = _vasiprintf_r (ptr, &p, format, ap);
> -  if (n == -1) return -1;
> +  p = _vasniprintf_r (ptr, buf, &n, format, ap);
> +  if (!p)
> +    return -1;
>    n = _write_r (ptr, fd, p, n);
> -  _free_r (ptr, p);
> +  if (p != buf)
> +    _free_r (ptr, p);
>    return n;
>  }
>  
> Index: libc/stdio/vdprintf.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/vdprintf.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 vdprintf.c
> --- libc/stdio/vdprintf.c	4 Apr 2007 18:32:49 -0000	1.2
> +++ libc/stdio/vdprintf.c	20 Apr 2007 15:00:37 -0000
> @@ -18,14 +18,16 @@ _DEFUN(_vdprintf_r, (ptr, fd, format, ap
>         va_list ap)
>  {
>    char *p;
> -  int n;
> +  char buf[512];
> +  size_t n = sizeof buf;
>  
>    _REENT_SMALL_CHECK_INIT (ptr);
> -  n = _vasprintf_r (ptr, &p, format, ap);
> -  if (n == -1)
> +  p = _vasnprintf_r (ptr, buf, &n, format, ap);
> +  if (!p)
>      return -1;
>    n = _write_r (ptr, fd, p, n);
> -  _free_r (ptr, p);
> +  if (p != buf)
> +    _free_r (ptr, p);
>    return n;
>  }
>  
>   



More information about the Newlib mailing list