This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
implement asnprintf
- From: Eric Blake <ebb9 at byu dot net>
- To: newlib at sources dot redhat dot com
- Date: Fri, 20 Apr 2007 13:11:01 -0600
- Subject: 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;
}