This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

implement asnprintf


-----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;
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]