--- This a C++ universal sprintf in the future. ** @pitfall: The behavior of vsnprintf between VS2013 and VS2015/2017 is different ** VS2013 or Unix-Like System will return -1 when buffer not enough, but VS2015/2017 will return the actural needed *length for buffer at this station ** The _vsnprintf behavior is compatible API which always return -1 when buffer isn't enough at VS2013/2015
| 56 | *reference: http://www.cplusplus.com/reference/cstdio/vsnprintf/ |
| 57 | */ |
| 58 | std::string vformat(const char* format, va_list ap) |
| 59 | { |
| 60 | #define AX_VSNPRINTF_BUFFER_LENGTH 512 |
| 61 | std::string buf(AX_VSNPRINTF_BUFFER_LENGTH, '\0'); |
| 62 | |
| 63 | va_list args; |
| 64 | va_copy(args, ap); |
| 65 | int nret = vsnprintf(&buf.front(), buf.length() + 1, format, args); |
| 66 | va_end(args); |
| 67 | |
| 68 | if (nret >= 0) |
| 69 | { |
| 70 | if ((unsigned int)nret < buf.length()) |
| 71 | { |
| 72 | buf.resize(nret); |
| 73 | } |
| 74 | else if ((unsigned int)nret > buf.length()) |
| 75 | { // handle return required length when buffer insufficient |
| 76 | buf.resize(nret); |
| 77 | |
| 78 | va_copy(args, ap); |
| 79 | nret = vsnprintf(&buf.front(), buf.length() + 1, format, args); |
| 80 | va_end(args); |
| 81 | } |
| 82 | // else equals, do nothing. |
| 83 | } |
| 84 | else |
| 85 | { // handle return -1 when buffer insufficient |
| 86 | /* |
| 87 | vs2013/older & glibc <= 2.0.6, they would return -1 when the output was truncated. |
| 88 | see: http://man7.org/linux/man-pages/man3/vsnprintf.3.html |
| 89 | */ |
| 90 | #if (defined(__linux__) && ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) || \ |
| 91 | (defined(_MSC_VER) && _MSC_VER < 1900) |
| 92 | enum : size_t |
| 93 | { |
| 94 | enlarge_limits = (1 << 20), // limits the buffer cost memory less than 2MB |
| 95 | }; |
| 96 | do |
| 97 | { |
| 98 | buf.resize(buf.length() << 1); |
| 99 | |
| 100 | va_copy(args, ap); |
| 101 | nret = vsnprintf(&buf.front(), buf.length() + 1, format, args); |
| 102 | va_end(args); |
| 103 | |
| 104 | } while (nret < 0 && buf.size() <= enlarge_limits); |
| 105 | if (nret > 0) |
| 106 | buf.resize(nret); |
| 107 | else |
| 108 | buf = "strfmt: an error is encountered!"; |
| 109 | #else |
| 110 | /* other standard implementation |
| 111 | see: http://www.cplusplus.com/reference/cstdio/vsnprintf/ |
| 112 | */ |
| 113 | buf = "strfmt: an error is encountered!"; |
| 114 | #endif |
| 115 | } |