# NAME

snprintf(3) - safe sprintf

# SYNOPSIS

        #include <slack/std.h>
        #ifndef HAVE_SNPRINTF
        #include <slack/snprintf.h>
        #endif

        int snprintf(char *str, size_t size, const char *format, ...);
        int vsnprintf(char *str, size_t size, const char *format, va_list args);

# DESCRIPTION

Safe version of sprintf(3) that doesn't suffer from buffer overruns.

`int snprintf(char *str, size_t size, const char *format, ...)`

  Writes output to the buffer, `str`, under control of the format string `format`, that specifies how subsequent arguments are converted for output. It is similar to sprintf(3), except that `size` specifies the maximum number of bytes to produce. The trailing `nul` byte is counted towards this limit, so you must allocate at least `size` bytes for `str`.

  If `size` is zero, nothing is written, and `str` may be `null`. Otherwise, output bytes beyond the `n-1`st are discarded rather than being written to `str`, and a `nul` byte is written at the end of the bytes actually written to `str`. If copying takes place between objects that overlap, the behaviour is undefined.

  On success, returns the number of bytes that would have been written had `size` been sufficiently large, not counting the terminating `nul` byte. Thus, the `nul`-terminated output has been completely written if and only if the return value is non-negative and less than `size`. On error, returns `-1` (i.e. encoding error).

  Note that if your system already has snprintf(3), but this implementation was installed anyway, it's because the system implementation has a broken return value. Some older implementations (e.g. glibc-2.0) return `-1` when the string is truncated rather than returning the number of bytes that would have been written had `size` been sufficiently large (not counting the terminating `nul` byte) as required by ISO/IEC 9899:1999(E).

`int vsnprintf(char *str, size_t size, const char *format, va_list args)`

  Equivalent to snprintf(3) with the variable argument list specified directly as for vsprintf(3).

# MT-Level

MT-Safe - provided that the locale is only set by the main thread before starting any other threads.

# EXAMPLES

How long is a piece of string?

        #include <slack/std.h>
        #ifndef HAVE_SNPRINTF
        #include <slack/snprintf.h>
        #endif

        int main(int ac, char **av)
        {
            char *str;
            int len;

            len = snprintf(NULL, 0, "%s %d", *av, ac);
            printf("this string has length %d\n", len);

            if (!(str = malloc((len + 1) * sizeof(char))))
                return EXIT_FAILURE;

            len = snprintf(str, len + 1, "%s %d", *av, ac);
            printf("%s %d\n", str, len);

            free(str);

            return EXIT_SUCCESS;
        }

Check if truncation occurred:

        #include <slack/std.h>
        #ifndef HAVE_SNPRINTF
        #include <slack/snprintf.h>
        #endif

        int main()
        {
            char str[16];
            int len;

            len = snprintf(str, 16, "%s %d", "hello world", 1000);
            printf("%s\n", str);

            if (len >= 16)
                printf("length truncated (from %d)\n", len);

            return EXIT_SUCCESS;
        }

Allocate memory only when needed to prevent truncation:

        #include <slack/std.h>
        #ifndef HAVE_SNPRINTF
        #include <slack/snprintf.h>
        #endif

        int main(int ac, char **av)
        {
            char buf[16];
            char *str = buf;
            char *extra = NULL;
            int len;

            if (!av[1])
                return EXIT_FAILURE;

            if ((len = snprintf(buf, 16, "%s", av[1])) >= 16)
                if (extra = malloc((len + 1) * sizeof(char)))
                    snprintf(str = extra, len + 1, "%s", av[1]);

            printf("%s\n", str);

            if (extra)
                free(extra);

            return EXIT_SUCCESS;
        }

# BUGS

The format control string, `format`, should be interpreted as a multi-byte character sequence but it is not. Apart from that, these functions comply with the ISO C 89 formatting requirements specified for the fprintf(3) function (section 7.9.6.1).

Even though snprintf(3) is an ISO C 99 function (section 7.19.6.5), this implementation does not support the new ISO C 99 formatting conversions or length modifiers (i.e. `%hh[diouxXn]`, `%ll[diouxXn]`, `%j[diouxXn]`, `%z[diouxXn]`, `%t[diouxXn]`, `%ls`, `%lc` and `%[aAF]`). The main reason is that the local system's sprintf(3) function is used to perform floating point formatting. If the local system can support `%[aA]`, then you must have C99 already, and so you must also have snprintf(3) already.

If snprintf(3) or vsnprintf(3) require more than `512` bytes of space in which to format a floating point number, but fail to allocate the required space, the floating point number will not be formatted at all, and processing will continue. There is no indication to the client that an error occurred. The chances of this happening are remote. It would take a field width or precision greater than the available memory to trigger this bug. Since there are only `15` significant digits in a double and only `18` significant digits in an `80` bit long double (`33` significant digits in a `128` bit long double), a precision larger than `15`/`18`/`33` serves no purpose, and a field width larger than the useful output serves no purpose.

# SEE ALSO

printf(3), sprintf(3), vsprintf(3)

# AUTHOR

2002-2021 raf <raf@raf.org>, 1998 Andrew Tridgell <tridge@samba.org>, 1998 Michael Elkins <me@cs.hmc.edu>, 1998 Thomas Roessler <roessler@guug.de>, 1996-1997 Brandon Long <blong@fiction.net>, 1995 Patrick Powell <papowell@astart.com>