Re: better snprintf replacement, anyone?

Peter Jeremy (peter.jeremy@ALCATEL.COM.AU)
Wed, 23 Jul 1997 07:30:22 +1000

On Tue, 22 Jul 1997 10:19:54 -0400, der Mouse <mouse@RODENTS.MONTREAL.QC.CA>
wrote:
>My reaction to this is "not using punched cards makes it hard to port
>to (other) legacy systems". The point beyond which a system is so
>legacy it's not worth even trying to support it, for me, includes
>systems without calls like snprintf.
Sun would probably not be totally pleased with having Solaris 2.5.1(*)
referred to as a legacy OS. I don't have ready access to other
current commercial C libraries. There's also the problem that (as far
as I know) [v]snprintf() is not part of the Standard C Library.

(*) Solaris 2.5.1 does include [v]snprintf, but only as `private'
routines with non-standard names. The routines weren't present
at all prior to Solaris 2.5.

On Tue, 22 Jul 1997 00:57:11 -0600, Theo de Raadt <deraadt@CVS.OPENBSD.ORG>
wrote:
>On 22nd July, Steve Coile wrote:
>> I would imagine that there are only a few cases were a program coulnd't
>> pre-determine the length of a string that would be generated by sprintf()
>> and malloc() enough memory to contain it all.

>Let me give you an example of what you suggest:
>
> if (strlen(a) + 1 + 10 + 3 + 1 + 10 + 4*sizeof(long) + 1 + strlen(b) +
> 1 + strlen(c) + 2 >= sizeof buf);
> sprintf(buf, "%s %d see %d %lx %s %s\n", a, i, j, p,
> b, c);
> else
> goto bail; /* I really just wanted to truncate the string... */

As a comment to support Theo's point of view, it's worth noting that
the above example includes about 6 errors. I realize Theo probably
whipped it up off the top of his head, but it does demonstrate the
difficulty of this approach. It should be something like:

#define N_DEC_DIGIT(type) ((((sizeof(type) * 8 - 1) * 30103 + 99999) \
/ 100000) + 1)

if (strlen(a) + 1 + N_DEC_DIGIT(int) + 5 + N_DEC_DIGIT(int) + 1 +
2*sizeof(long) + 1 + strlen(b) + 1 + strlen(c) + 2 <= sizeof buf)
{
sprintf(buf, "%s %d see %d %lx %s %s\n", a, i, j, p, b, c);
} else {
goto bail; /* I really just wanted to truncate the string... */
}

(For those puzzled about N_DEC_DIGIT: log10(2) ~= .30103 and the sign bit
doesn't count).

Peter

---
Peter Jeremy (VK2PJ)                    peter.jeremy@alcatel.com.au
Alcatel Australia Limited
41 Mandible St                          Phone: +61 2 9690 5019
ALEXANDRIA  NSW  2015                   Fax:   +61 2 9690 5247