If this is VS prior to 2015 or MinGW, we can't trust snprintf(); we have
to use _snprintf_s(), but that requires us to insert _TRUNCATE as an
argument after the buffer and buffer length and before the format string
and arguments, if any, to the format string.
That means we need to use a vararg macro; however, if we make the format
string a regular argument to the macro, that means that, if there are no
arguments *after* the format string, you end up with an argument list to
_snprintf_s() that ends with "fmt, ", and that's not valid C.
*If* we knew this was GCC or Clang, we could use a GNU C-specific hack,
wherein, if __VA_ARGS__ is preceded by ## and there's a comma before
that, the comma is removed if __VA_ARGS__ is empty, but this might be
Microsoft's C compiler in a version of Visual Studio prior to VS 2015,
which might not support that.
So we have to just have the macro take, as the ... arguments, the format
string and its arguments.
Addresses GitHub issue #713.
* VS prior to 2015, or MingGW; assume we have _snprintf_s() and
* _vsnprintf_s(), which guarantee null termination.
*/
- #define nd_snprintf(buf, buflen, fmt, ...) \
- _snprintf_s(buf, buflen, _TRUNCATE, fmt, __VA_ARGS__)
+ #define nd_snprintf(buf, buflen, ...) \
+ _snprintf_s(buf, buflen, _TRUNCATE, __VA_ARGS__)
#define nd_vsnprintf(buf, buflen, fmt, ap) \
_vsnprintf_s(buf, buflen, _TRUNCATE, fmt, ap)
#endif /* defined(_MSC_VER) && _MSC_VER >= 1900 */