[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [v]asnprintf and portability
From: |
Bruno Haible |
Subject: |
Re: [v]asnprintf and portability |
Date: |
Tue, 13 Mar 2007 21:45:48 +0100 |
User-agent: |
KMail/1.9.1 |
Eric Blake wrote:
> I am not aware of any other platform that provides a native asnprintf - is it
> a
> gnulib invention?
Yes it is. A bit of history:
- Mark Martinec was probably the first to implement a vasnprintf()
function in 2000. See http://www.ijs.si/software/snprintf/ . I wasn't
aware of it until today.
- In 1999, when I made libutf8, that included some *printf functions that
could support wide strings (wchar_t *). Here I had 5 copies of very
similar code in
vfprintf.c
vfwprintf.c
vsprintf.c
vsnprintf.c
vswprintf.c
- In spring 2002, when I started working on the stdio part of a Unicode
string library, I wanted to have a single function at the base of the
many *printf routines. The GNU libc and BSD libcs also have such a
function: for them it's the vfprintf() function. But since implementing
sprintf on top of vfprintf requires a "memory stream"/"string stream"
data type, which is not portably available, I had to base the routine
on strings rather than on FILE streams.
- In October 2002, I reused this code for libasprintf (part of gettext).
- In June 2003, it also became part of libintl when built on NetBSD or
mingw.
> If it is a gnulib invention, then it almost seems odd to have vasnprintf
> vs. vasnprintf-posix modules, since POSIX makes no requirements on it -
> why not always support full semantics?
Few users need the 'a' and 'A' directives. Especially libintl doesn't need it.
> The newlib list wants to know why it is worth making asnprintf part of the
> library. My argument is as follows:
> ... The other is that the argument list must
> be processed twice, which involves some non-trivial computation time,
> particularly on double arguments, in order to compute the length
> independently from generating the output.
That's the main point. vasnprintf has 3 properties:
1) It is safe to use (no buffer overflow risk).
2) It allows to produce the result while processing the arguments only
once, regardless how small or large the result will be.
3) It avoids calling malloc() when the result is small.
sprintf() has the properties 2) and 3), but not 1).
snprintf() has the properties 1) and 3), but not 2).
asprintf() has the properties 1) and 2), but not 3).
asnprintf() has all three properties.
Here for example the code to implement vfprintf based on vasnprintf:
char buf[2000];
char *output;
size_t len;
size_t lenbuf = sizeof (buf);
output = vasnprintf (buf, &lenbuf, format, args);
len = lenbuf;
if (!output)
...
if (fwrite (output, 1, len, fp) < len)
...
You clearly see that such a safe, efficient, one-pass processing is only
possible when all three properties above are present.
Bruno