Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:35:14

0001 /*
0002  *             Copyright Andrey Semashev 2022.
0003  * Distributed under the Boost Software License, Version 1.0.
0004  *    (See accompanying file LICENSE_1_0.txt or copy at
0005  *          http://www.boost.org/LICENSE_1_0.txt)
0006  */
0007 /*!
0008  * \file   snprintf.hpp
0009  * \author Andrey Semashev
0010  * \date   06.12.2022
0011  *
0012  * \brief  The header provides more portable definition of snprintf and vsnprintf,
0013  *         as well as \c wchar_t counterparts.
0014  */
0015 
0016 #ifndef BOOST_CORE_SNPRINTF_HPP_INCLUDED_
0017 #define BOOST_CORE_SNPRINTF_HPP_INCLUDED_
0018 
0019 #include <stdio.h>
0020 #include <wchar.h>
0021 #include <boost/config.hpp>
0022 
0023 #ifdef BOOST_HAS_PRAGMA_ONCE
0024 #pragma once
0025 #endif
0026 
0027 #if defined(__MINGW32__)
0028 
0029 #include <cstddef>
0030 #include <cstdarg>
0031 #if !defined(__MINGW64_VERSION_MAJOR)
0032 #include <climits>
0033 #endif
0034 
0035 // MinGW32 and MinGW-w64 provide their own snprintf implementations that are compliant with the C standard.
0036 #define BOOST_CORE_DETAIL_MINGW_SNPRINTF
0037 
0038 #elif (defined(BOOST_MSSTL_VERSION) && BOOST_MSSTL_VERSION < 140)
0039 
0040 #include <cstddef>
0041 #include <cstdarg>
0042 #include <climits>
0043 
0044 // MSVC snprintfs are not conforming but they are good enough for typical use cases.
0045 #define BOOST_CORE_DETAIL_MSVC_LEGACY_SNPRINTF
0046 
0047 #endif
0048 
0049 namespace boost {
0050 
0051 namespace core {
0052 
0053 #if defined(BOOST_CORE_DETAIL_MINGW_SNPRINTF) || defined(BOOST_CORE_DETAIL_MSVC_LEGACY_SNPRINTF)
0054 
0055 #if defined(BOOST_CORE_DETAIL_MINGW_SNPRINTF)
0056 
0057 inline int vsnprintf(char* buf, std::size_t size, const char* format, std::va_list args)
0058 {
0059     return __mingw_vsnprintf(buf, size, format, args);
0060 }
0061 
0062 inline int vswprintf(wchar_t* buf, std::size_t size, const wchar_t* format, std::va_list args)
0063 {
0064 #if defined(__MINGW64_VERSION_MAJOR)
0065     int res = __mingw_vsnwprintf(buf, size, format, args);
0066     // __mingw_vsnwprintf returns the number of characters to be printed, but (v)swprintf is expected to return -1 on truncation
0067     if (static_cast< unsigned int >(res) >= size)
0068         res = -1;
0069     return res;
0070 #else
0071     // Legacy MinGW32 does not provide __mingw_vsnwprintf, so use _vsnwprintf from MSVC CRT
0072     if (BOOST_UNLIKELY(size == 0u || size > static_cast< std::size_t >(INT_MAX)))
0073         return -1;
0074 
0075     int res = _vsnwprintf(buf, size, format, args);
0076     // (v)swprintf is expected to return -1 on truncation, so we only need to ensure the output is null-terminated
0077     if (static_cast< unsigned int >(res) >= size)
0078     {
0079         buf[size - 1u] = L'\0';
0080         res = -1;
0081     }
0082 
0083     return res;
0084 #endif
0085 }
0086 
0087 #elif defined(BOOST_CORE_DETAIL_MSVC_LEGACY_SNPRINTF)
0088 
0089 #if defined(_MSC_VER)
0090 #pragma warning(push)
0091 // '_vsnprintf': This function or variable may be unsafe. Consider using _vsnprintf_s instead.
0092 #pragma warning(disable: 4996)
0093 #endif
0094 
0095 inline int vsnprintf(char* buf, std::size_t size, const char* format, std::va_list args)
0096 {
0097     if (BOOST_UNLIKELY(size == 0u))
0098         return 0;
0099     if (BOOST_UNLIKELY(size > static_cast< std::size_t >(INT_MAX)))
0100         return -1;
0101 
0102     buf[size - 1u] = '\0';
0103     int res = _vsnprintf(buf, size, format, args);
0104     if (static_cast< unsigned int >(res) >= size)
0105     {
0106         // _vsnprintf returns -1 if the output was truncated and in case of other errors.
0107         // Detect truncation by checking whether the output buffer was written over entirely.
0108         if (buf[size - 1u] != '\0')
0109         {
0110             buf[size - 1u] = '\0';
0111             res = static_cast< int >(size);
0112         }
0113     }
0114 
0115     return res;
0116 }
0117 
0118 inline int vswprintf(wchar_t* buf, std::size_t size, const wchar_t* format, std::va_list args)
0119 {
0120     if (BOOST_UNLIKELY(size == 0u || size > static_cast< std::size_t >(INT_MAX)))
0121         return -1;
0122 
0123     int res = _vsnwprintf(buf, size, format, args);
0124     // (v)swprintf is expected to return -1 on truncation, so we only need to ensure the output is null-terminated
0125     if (static_cast< unsigned int >(res) >= size)
0126     {
0127         buf[size - 1u] = L'\0';
0128         res = -1;
0129     }
0130 
0131     return res;
0132 }
0133 
0134 #if defined(_MSC_VER)
0135 #pragma warning(pop)
0136 #endif
0137 
0138 #endif
0139 
0140 inline int snprintf(char* buf, std::size_t size, const char* format, ...)
0141 {
0142     std::va_list args;
0143     va_start(args, format);
0144     int res = vsnprintf(buf, size, format, args);
0145     va_end(args);
0146     return res;
0147 }
0148 
0149 inline int swprintf(wchar_t* buf, std::size_t size, const wchar_t* format, ...)
0150 {
0151     std::va_list args;
0152     va_start(args, format);
0153     int res = vswprintf(buf, size, format, args);
0154     va_end(args);
0155     return res;
0156 }
0157 
0158 #else // defined(BOOST_CORE_DETAIL_MINGW_SNPRINTF) || defined(BOOST_CORE_DETAIL_MSVC_LEGACY_SNPRINTF)
0159 
0160 // Standard-conforming compilers already have the correct snprintfs
0161 using ::snprintf;
0162 using ::vsnprintf;
0163 
0164 using ::swprintf;
0165 using ::vswprintf;
0166 
0167 #endif // defined(BOOST_CORE_DETAIL_MINGW_SNPRINTF) || defined(BOOST_CORE_DETAIL_MSVC_LEGACY_SNPRINTF)
0168 
0169 } // namespace core
0170 
0171 } // namespace boost
0172 
0173 #endif // BOOST_CORE_SNPRINTF_HPP_INCLUDED_