develooper Front page | perl.perl5.porters | Postings from January 2006

Re: [PATCH] snprintf() and vsnprintf()

Thread Previous | Thread Next
From:
H.Merijn Brand
Date:
January 5, 2006 13:07
Subject:
Re: [PATCH] snprintf() and vsnprintf()
Message ID:
20060105220807.3b0b49db@pc09
On Mon, 02 Jan 2006 10:49:01 -0800, Russ Allbery <rra@stanford.edu> wrote:

> Steve Peters <steve@fisharerojo.org> writes:
> 
> > Adding support for snprintf() and vsnprintf() isn't too difficult to do
> > if you optimistically (or foolishly) assume these functions both return
> > int's as POSIX specifies.  As both functions are relatively new to most
> > libc's, I'll assume the standards are being followed for now.
> 
> Please note that the following incompatibilities with ISO C99 snprintf are
> common in practice:
> 
>  * Returning -1 rather than size when trying to print a string that's
>    longer than the buffer size.
> 
>  * Not supporting snprintf(NULL, 0, <format>, ...) to size the result and
>    instead always failing on that form.
> 
>  * Not nul-terminating the buffer if the string was longer than the
>    buffer.

As per Jarkko's suggestion, with a little more cleanups, I have now applied
this in Change #26668 to blead:

Change 26668 by merijn@merijn-pc09 on 2006/01/05 21:04:32

        Test if the probed availability of v?snprintf () is
        actually usable. Thanks to Russ and Jarkko.

Affected files ...

... //depot/perl/Configure#597 edit

Differences ...

==== //depot/perl/Configure#597 (xtext) ====

29c29
< # Generated on Tue Jan  3 16:44:36 CET 2006 [metaconfig 3.0 PL70]
---
> # Generated on Thu Jan  5 22:03:19 CET 2006 [metaconfig 3.0 PL70]
16548a16549,16605
> case "$d_snprintf-$d_vsnprintf" in
> "$define-$define")
>     $cat <<EOM
> Checking whether your snprintf() and vsnprintf() work okay...
> EOM
>     $cat >try.c <<'EOCP'
> /* v?snprintf testing logic courtesy of Russ Allbery.
>  * According to C99:
>  * - if the buffer is too short it still must be \0-terminated
>  * - if the buffer is too short the potentially required length
>  *   must be returned and not -1
>  * - if the buffer is NULL the potentially required length
>  *   must be returned and not -1 or core dump
>  */
> #include <stdio.h>
> #include <stdarg.h>
>
> char buf[2];
>
> int test (char *format, ...)
> {
>     va_list args;
>     int count;
>
>     va_start (args, format);
>     count = vsnprintf (buf, sizeof buf, format, args);
>     va_end (args);
>     return count;
> }
>
> int main ()
> {
>     return ((test ("%s", "abcd") == 4 && buf[0] == 'a' && buf[1] == '\0'
>              && snprintf (NULL, 0, "%s", "abcd") == 4) ? 0 : 1);
> }
> EOCP
>     set try
>     if eval $compile; then
>       `$run ./try`
>       case "$?" in
>       0) echo "Your snprintf() and vsnprintf() seem to be working okay." ;;
>       *) cat <<EOM >&4
> Your snprintf() and snprintf() don't seem to be working okay.
> EOM
>          d_snprintf="$undef"
>          d_vsnprintf="$undef"
>          ;;
>       esac
>     else
>       echo "(I can't seem to compile the test program--assuming they don't)"
>       d_snprintf="$undef"
>       d_vsnprintf="$undef"
>     fi
>     $rm -f try.* try core core.try.*
>     ;;
> esac
>

> I use the following Autoconf probe and then supply a replacement snprintf
> if it fails in software I write.
> 
> dnl snprintf.m4 -- Test for a working C99 snprintf.
> dnl $Id: snprintf.m4 2312 2005-12-22 19:24:13Z rra $
> dnl
> dnl Check for a working snprintf.  Some systems have an snprintf that
> doesn't dnl nul-terminate if the buffer isn't large enough.  Others return
> -1 if the dnl string doesn't fit into the buffer instead of returning the
> number of dnl characters that would have been formatted.  Still others
> don't support dnl NULL as the buffer argument (just to get a count of the
> formatted length). dnl
> dnl Provides RRA_FUNC_SNPRINTF, which adds snprintf.o to LIBOBJS unless a
> dnl fully working snprintf is found.
> 
> dnl Source used by RRA_FUNC_SNPRINTF.
> define([_RRA_FUNC_SNPRINTF_SOURCE],
> [[#include <stdio.h>
> #include <stdarg.h>
> 
> char buf[2];
> 
> int
> test(char *format, ...)
> {
>     va_list args;
>     int count;
> 
>     va_start(args, format);
>     count = vsnprintf(buf, sizeof buf, format, args);
>     va_end(args);
>     return count;
> }
> 
> int
> main()
> {
>     return ((test("%s", "abcd") == 4 && buf[0] == 'a' && buf[1] == '\0'
>              && snprintf(NULL, 0, "%s", "abcd") == 4) ? 0 : 1);
> }]])
> 
> dnl The user-callable test.
> AC_DEFUN([RRA_FUNC_SNPRINTF],
> [AC_CACHE_CHECK([for working snprintf], [rra_cv_func_snprintf_works],
>     [AC_TRY_RUN(_RRA_FUNC_SNPRINTF_SOURCE(),
>         [rra_cv_func_snprintf_works=yes],
>         [rra_cv_func_snprintf_works=no],
>         [rra_cv_func_snprintf_works=no])])
> if test "$rra_cv_func_snprintf_works" = yes ; then
>     AC_DEFINE([HAVE_SNPRINTF], 1,
>         [Define if your system has a working snprintf function.])
> else
>     AC_LIBOBJ([snprintf])
> fi])
> 


-- 
H.Merijn Brand        Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using Perl 5.6.2, 5.8.0, 5.8.5, & 5.9.2  on HP-UX 10.20, 11.00 & 11.11,
 AIX 4.3 & 5.2, SuSE 9.2 & 9.3, and Cygwin. http://www.cmve.net/~merijn
Smoking perl: http://www.test-smoke.org,    perl QA: http://qa.perl.org
 reports  to: smokers-reports@perl.org,                perl-qa@perl.org

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About