diff --git a/include/stdex/string.hpp b/include/stdex/string.hpp index ae4831c41..4c0e03735 100644 --- a/include/stdex/string.hpp +++ b/include/stdex/string.hpp @@ -804,4 +804,97 @@ namespace stdex return (size_t)strtou32(str, count, end, radix); #endif } + + /// \cond internal + inline int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg) + { +#if _MSC_VER <= 1600 +#pragma warning(suppress: 4996) + return _vsnprintf(str, capacity, format, arg); +#else +#pragma warning(suppress: 4996) + return ::vsnprintf(str, capacity, format, arg); +#endif + } + + inline int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const wchar_t *format, _In_ va_list arg) noexcept + { +#pragma warning(suppress: 4996) + return _vsnwprintf(str, capacity, format, arg); + } + /// \endcond + + /// + /// Formats string using `printf()`. + /// + /// \param[out] str String to append formatted text + /// \param[in ] format String template using `printf()` style + /// \param[in ] arg Arguments to `format` + /// + template + inline void vappendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg) + { + _Elem buf[1024/sizeof(_Elem)]; + + // Try with stack buffer first. + int count = vsnprintf(buf, _countof(buf) - 1, format, arg); + if (count >= 0) { + // Copy from stack. + str.append(buf, count); + } else { + for (size_t capacity = 2*1024/sizeof(_Elem);; capacity *= 2) { + // Allocate on heap and retry. + auto buf_dyn = std::make_unique<_Elem[]>(capacity); + count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg); + if (count >= 0) { + str.append(buf_dyn.get(), count); + break; + } + } + } + } + + /// + /// Formats string using `printf()`. + /// + /// \param[out] str String to append formatted text + /// \param[in ] format String template using `printf()` style + /// + template + inline void appendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) + { + va_list arg; + va_start(arg, format); + vappendf(str, format, arg); + va_end(arg); + } + + /// + /// Formats string using `printf()`. + /// + /// \param[out] str Formatted string + /// \param[in ] format String template using `printf()` style + /// \param[in ] arg Arguments to `format` + /// + template + inline void vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg) + { + str.clear(); + appendf(str, format, arg); + } + + /// + /// Formats string using `printf()`. + /// + /// \param[out] str Formatted string + /// \param[in ] format String template using `printf()` style + /// + template + inline void sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) + { + va_list arg; + va_start(arg, format); + vsprintf(str, format, arg); + va_end(arg); + } } \ No newline at end of file