1 /************************************************************************** 2 Copyright: 3 (C) 2009 - 2012 Alexander Shaduri <ashaduri 'at' gmail.com> 4 License: See LICENSE_zlib.txt file 5 ***************************************************************************/ 6 /// \file 7 /// \author Alexander Shaduri 8 /// \ingroup hz 9 /// \weakgroup hz 10 /// @{ 11 12 #ifndef HZ_PORTABLE_SNPRINTF_H 13 #define HZ_PORTABLE_SNPRINTF_H 14 15 #include "hz_config.h" // feature macros 16 17 18 /** 19 \file 20 Compilation options: 21 - Define \c ENABLE_GLIB to 1 to enable glib-related code (portable ISO-compatible (v)snprintf). 22 23 Keep in mind that these format types are non-portable (the first one is MS variant, 24 the second one is standard): 25 - %I64d, %lld (long long int), 26 - %I64u, %llu (unsigned long long int), 27 - %f, %Lf (long double; needs casting to double under non-ANSI mingw if using %f). 28 */ 29 30 31 namespace hz { 32 33 34 // Note: There are macros, so they are not namespaced. 35 36 37 /// \def HAVE_PORTABLE_SNPRINTF_MS 38 /// If 1, portable_snprintf() and portable_vsnprintf() accept I64d, I64u. 39 /// Users are expected to check this macro to see if the format is supported. 40 41 /// \def HAVE_PORTABLE_SNPRINTF_ISO 42 /// If 1, portable_snprintf() and portable_vsnprintf() accept lld, llu, Lf. 43 /// Users are expected to check this macro to see if the format is supported. 44 45 46 47 /// \def portable_snprintf(buf, buf_size, ...) 48 /// snprintf() wrapper that always behaves according to ISO standard in terms of 0-termination. 49 /// Note that this is a macro, and therefore not namespaced. 50 /// Use it like this: 51 /// \code void portable_snprintf(char *str, size_t size, const char *format, ...); \endcode 52 53 #if defined ENABLE_GLIB && ENABLE_GLIB 54 #include <glib.h> // g_snprintf 55 56 // It's ISO-compatible 57 #define portable_snprintf(buf, buf_size, ...) \ 58 (void)g_snprintf((buf), (buf_size), __VA_ARGS__) 59 60 #define HAVE_PORTABLE_SNPRINTF_MS 0 61 #define HAVE_PORTABLE_SNPRINTF_ISO 1 62 63 #elif defined HAVE_ISO_STDIO && HAVE_ISO_STDIO 64 // mingw/ISO, all non-windows platforms. 65 #include <cstdio> // for cstdio 66 #include <stdio.h> // snprintf 67 68 #define portable_snprintf(buf, buf_size, ...) \ 69 (void)snprintf((buf), (buf_size), __VA_ARGS__) 70 71 // mingw/ISO has both the MS and ISO specifiers 72 #if defined _WIN32 && defined __GNUC__ 73 #define HAVE_PORTABLE_SNPRINTF_MS 1 74 #else 75 #define HAVE_PORTABLE_SNPRINTF_MS 0 76 #endif 77 78 #define HAVE_PORTABLE_SNPRINTF_ISO 1 79 80 #elif defined HAVE_WIN_SE_FUNCS && HAVE_WIN_SE_FUNCS 81 #include <cstdio> // for cstdio 82 #include <stdio.h> // _snprintf_s 83 84 // writes at most buf_size bytes, always including 0. 85 #define portable_snprintf(buf, buf_size, ...) \ 86 (void)_snprintf_s((buf), (buf_size), _TRUNCATE, __VA_ARGS__) 87 88 #define HAVE_PORTABLE_SNPRINTF_MS 1 89 #define HAVE_PORTABLE_SNPRINTF_ISO 0 90 91 #elif defined HAVE__SNPRINTF && HAVE__SNPRINTF 92 // Prefer snprintf() to _snprintf() if we're sure it's good. 93 // Note that old versions of mingw used to define snprintf() as _snprintf(), 94 // which is not proper. 95 96 #include <cstdio> // for cstdio 97 #include <stdio.h> // _snprintf 98 99 // _snprintf() writes at most buf_size-1 bytes. the buffer should be zeroed out 100 // beforehand. 101 #define portable_snprintf(buf, buf_size, ...) \ 102 (void)((_snprintf((buf), (buf_size) - 1, __VA_ARGS__) == ((buf_size) - 1)) && ((buf)[(buf_size)-1] = '\0')) 103 104 #define HAVE_PORTABLE_SNPRINTF_MS 0 105 #define HAVE_PORTABLE_SNPRINTF_ISO 1 106 107 #else 108 #error Cannot find suitable snprintf() implementation for portable_snprintf() 109 110 #endif 111 112 113 114 115 /// \def portable_vsnprintf(buf, buf_size, ...) 116 /// vsnprintf() wrapper that always behaves according to ISO standard in terms of 0-termination. 117 /// Note that this is a macro, and therefore not namespaced. 118 /// Use it like this: 119 /// \code void portable_vsnprintf(char *str, size_t size, const char *format, va_list ap); \endcode 120 121 #if defined ENABLE_GLIB && ENABLE_GLIB 122 #include <glib.h> // g_vsnprintf 123 124 // It's ISO-compatible 125 #define portable_vsnprintf(buf, buf_size, format, ap) \ 126 (void)g_vsnprintf((buf), (buf_size), (format), (ap)) 127 128 #define HAVE_PORTABLE_VSNPRINTF_MS 0 129 #define HAVE_PORTABLE_VSNPRINTF_ISO 1 130 131 #elif defined HAVE_ISO_STDIO && HAVE_ISO_STDIO 132 #include <cstdio> // for cstdio 133 #include <stdio.h> // vsnprintf (mingw, posix(?)) 134 #include <cstdarg> // for cstdarg 135 #include <stdarg.h> // vsnprintf (gnu) 136 137 #define portable_vsnprintf(buf, buf_size, format, ap) \ 138 (void)vsnprintf((buf), (buf_size), (format), (ap)) 139 140 // mingw/ISO has both the MS and ISO specifiers 141 #if defined _WIN32 && defined __GNUC__ 142 #define HAVE_PORTABLE_VSNPRINTF_MS 1 143 #else 144 #define HAVE_PORTABLE_VSNPRINTF_MS 0 145 #endif 146 #define HAVE_PORTABLE_VSNPRINTF_ISO 1 147 148 #elif defined HAVE_WIN_SE_FUNCS && HAVE_WIN_SE_FUNCS 149 #include <cstdio> // for cstdio 150 #include <stdio.h> // _vsnprintf_s 151 152 // writes at most buf_size bytes, always including 0. 153 #define portable_vsnprintf(buf, buf_size, format, ap) \ 154 (void)vsnprintf_s((buf), (buf_size), _TRUNCATE, (format), (ap)) 155 156 #define HAVE_PORTABLE_VSNPRINTF_MS 1 157 #define HAVE_PORTABLE_VSNPRINTF_ISO 0 158 159 #elif defined HAVE__VSNPRINTF && HAVE__VSNPRINTF 160 // prefer snprintf() to _snprintf() if we're sure it's good. 161 162 #include <cstdio> // for cstdio 163 #include <stdio.h> // _vsnprintf 164 #include <cstdarg> // for cstdarg 165 #include <stdarg.h> // _vsnprintf 166 167 // _vsnprintf() writes at most buf_size-1 bytes. the buffer should be zeroed out 168 // beforehand. 169 // Note that MS's vsnprintf() (which is the same as their _vsnprintf()) 170 // doesn't always write 0. 171 // We use _vsnprintf() instead of vsnprintf() to avoid using the proper vsnprintf() 172 // by chance (_vsnprintf() is always broken, vsnprintf() may not be). 173 #define portable_vsnprintf(buf, buf_size, format, ap) \ 174 (void)((_vsnprintf((buf), (buf_size) - 1, (format), (ap)) == ((buf_size) - 1)) && ((buf)[(buf_size)-1] = '\0')) 175 176 #define HAVE_PORTABLE_VSNPRINTF_MS 1 177 #define HAVE_PORTABLE_VSNPRINTF_ISO 0 178 179 #else 180 #error Cannot find suitable vsnprintf() implementation for portable_vsnprintf() 181 #endif 182 183 184 185 186 187 } // ns 188 189 190 191 192 193 #endif 194 195 /// @} 196