Skip to main content
Add attribute format to va_list version
Source Link
Toby Speight
  • 81.8k
  • 14
  • 101
  • 309
#ifdef __GNUC__
#define attribute(x) __attribute__(x)
#else
#define attribute(x)
#endif

namespace alx {

    // va_list version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, va_list ap)
        attribute((format (printf, 4, 0)));

    // general version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, ...)
#ifdef __GNUC__
        __attribute__attribute((format (printf, 4, 5)))
#endif
        ;

    // deduce size from buffer argument
    template<std::size_t N>
    int sprintf(char(&buff)[N], std::ptrdiff_t *written,
                 const char *fmt, ...)
#ifdef __GNUC__
        __attribute__attribute((format (printf, 3, 4)))
#endif
        ;
}

#undef attribute

// template definition
template<std::size_t N>
int alx::sprintf(char(&buff)[N], std::ptrdiff_t *written,
                  const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int result = alx::sprintf(buff, written, N, fmt, ap);
    va_end(ap);
    return result;
}
namespace alx {

    // va_list version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, va_list ap);

    // general version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, ...)
#ifdef __GNUC__
        __attribute__((format (printf, 4, 5)))
#endif
        ;

    // deduce size from buffer argument
    template<std::size_t N>
    int sprintf(char(&buff)[N], std::ptrdiff_t *written,
                 const char *fmt, ...)
#ifdef __GNUC__
        __attribute__((format (printf, 3, 4)))
#endif
        ;
}

// template definition
template<std::size_t N>
int alx::sprintf(char(&buff)[N], std::ptrdiff_t *written,
                  const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int result = alx::sprintf(buff, written, N, fmt, ap);
    va_end(ap);
    return result;
}
#ifdef __GNUC__
#define attribute(x) __attribute__(x)
#else
#define attribute(x)
#endif

namespace alx {

    // va_list version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, va_list ap)
        attribute((format (printf, 4, 0)));

    // general version
    int sprintf(char *str, std::ptrdiff_t *written,
                  std::ptrdiff_t buf_size, const char *format, ...)
        attribute((format (printf, 4, 5)));

    // deduce size from buffer argument
    template<std::size_t N>
    int sprintf(char(&buff)[N], std::ptrdiff_t *written,
                 const char *fmt, ...)
        attribute((format (printf, 3, 4)));
}

#undef attribute

// template definition
template<std::size_t N>
int alx::sprintf(char(&buff)[N], std::ptrdiff_t *written,
                  const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int result = alx::sprintf(buff, written, N, fmt, ap);
    va_end(ap);
    return result;
}
buf_size needs to have room for the null
Source Link
Toby Speight
  • 81.8k
  • 14
  • 101
  • 309
int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    if (buf_size <<= 0) {
        return - (errno = EOVERFLOW);
    }

    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}
int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    if (buf_size < 0) {
        return - (errno = EOVERFLOW);
    }

    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}
int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    if (buf_size <= 0) {
        return - (errno = EOVERFLOW);
    }

    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}
Clearer about storing zero; move buf_size test to common function
Source Link
Toby Speight
  • 81.8k
  • 14
  • 101
  • 309

When std::vsnprintf() returns a negative result, we shouldn't be storing that in written - it makes more sense to set written tostore zero instead, and ensure we write an empty string.

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    if (buf_size < 0) {
        return - (errno = EOVERFLOW);
    }

    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    if (buf_size < 0) {
        return - (errno = EOVERFLOW);
    }

    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}

When std::vsnprintf() returns a negative result, we shouldn't be storing that in written - it makes more sense to set written to zero instead.

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    if (buf_size < 0) {
        return - (errno = EOVERFLOW);
    }

    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}

When std::vsnprintf() returns a negative result, we shouldn't be storing that in written - it makes more sense to store zero instead, and ensure we write an empty string.

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, va_list ap)
{
    if (buf_size < 0) {
        return - (errno = EOVERFLOW);
    }

    int len = std::vsnprintf(str, buf_size, format, ap);

    if (len < 0) {
        *str = '\0';
        if (written) {
            *written = 0;
        }
        return -errno;
    }

    if (len >= buf_size) {
        if (written) {
            *written = buf_size - 1;
        }
        return - (errno = EOVERFLOW);
    }

    if (written) {
        *written = len;
    }

    return  0;
}

int alx::sprintf(char *str, std::ptrdiff_t *written,
                 std::ptrdiff_t buf_size, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = alx::sprintf(str, written, buf_size, format, ap);
    va_end(ap);
    return result;
}
vsnprintf is in std
Source Link
Toby Speight
  • 81.8k
  • 14
  • 101
  • 309
Loading
Source Link
Toby Speight
  • 81.8k
  • 14
  • 101
  • 309
Loading