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

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

Thread Previous | Thread Next
From:
Russ Allbery
Date:
January 2, 2006 10:49
Subject:
Re: [PATCH] snprintf() and vsnprintf()
Message ID:
87mzie4g9u.fsf@windlord.stanford.edu
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.

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])

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>

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