Brian Silverman | 8ed424f | 2018-08-04 23:36:27 -0700 | [diff] [blame^] | 1 | // ------------------------------------------------------------------------------ |
| 2 | // format_matrix.cpp : tool to check for regressions between boost format |
| 3 | // releases and compare format specification handling |
| 4 | // ------------------------------------------------------------------------------ |
| 5 | |
| 6 | // Copyright 2017 James E. King, III. Use, modification, and distribution |
| 7 | // are subject to the Boost Software License, Version 1.0. (See accompanying |
| 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 9 | |
| 10 | // See http://www.boost.org/libs/format for library home page |
| 11 | |
| 12 | // ------------------------------------------------------------------------------ |
| 13 | // reference (ISO C99) : http://en.cppreference.com/w/cpp/io/c/fprintf |
| 14 | // reference (Java) : http://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html |
| 15 | // reference (Microsoft) : https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions |
| 16 | // reference (POSIX 2008): http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html |
| 17 | |
| 18 | #include <boost/array.hpp> |
| 19 | #include <boost/config.hpp> |
| 20 | #include <boost/cstdint.hpp> |
| 21 | #include <boost/filesystem/path.hpp> |
| 22 | #include <boost/format.hpp> |
| 23 | #include <boost/io/ios_state.hpp> |
| 24 | #include <boost/predef.h> |
| 25 | #include <boost/program_options.hpp> |
| 26 | #include <cerrno> |
| 27 | #include <climits> |
| 28 | #include <clocale> |
| 29 | #if BOOST_COMP_MSVC && BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) >= 19 |
| 30 | #include <corecrt.h> // wint_t |
| 31 | #endif |
| 32 | #include <cstdio> |
| 33 | #include <cstdlib> |
| 34 | #include <cstring> |
| 35 | #include <cwchar> |
| 36 | #include <fstream> |
| 37 | #include <iomanip> |
| 38 | #include <iostream> |
| 39 | #include <math.h> |
| 40 | |
| 41 | #define SNPRINTF snprintf |
| 42 | #if BOOST_COMP_MSVC && BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) < 19 |
| 43 | #undef SNPRINTF |
| 44 | #define SNPRINTF _snprintf |
| 45 | #endif |
| 46 | |
| 47 | namespace fs = boost::filesystem; |
| 48 | namespace po = boost::program_options; |
| 49 | using namespace std; |
| 50 | |
| 51 | namespace matrix |
| 52 | { |
| 53 | |
| 54 | enum interop_datatype |
| 55 | { |
| 56 | // special types: |
| 57 | ID_UNDEF, // undefined behavior according to the spec, so combination is not tested |
| 58 | ID_NOTSUP, // behavior is not supported and therefore not tested currently |
| 59 | |
| 60 | // boolean type values: |
| 61 | ID_BOOLF, // false |
| 62 | ID_BOOLT, // true |
| 63 | |
| 64 | // string type values: |
| 65 | ID_CHAR, // single signed character |
| 66 | ID_UCHAR, // single unsigned character |
| 67 | ID_WCHAR, // single wide character |
| 68 | ID_STR, // C style string |
| 69 | ID_WSTR, // C style wide string |
| 70 | |
| 71 | // integer type values: |
| 72 | ID_ZERO, // zero value |
| 73 | ID_BYTE, // int8_t |
| 74 | ID_UBYTE, // uint8_t |
| 75 | ID_SHORT, // signed short |
| 76 | ID_USHORT, // unsigned short |
| 77 | ID_INT, // signed integer |
| 78 | ID_UINT, // unsigned integer |
| 79 | ID_LONG, // signed long |
| 80 | ID_ULONG, // unsigned long |
| 81 | ID_LLONG, // signed long long |
| 82 | ID_ULLONG, // unsigned long long |
| 83 | ID_INTMAX, // intmax_t |
| 84 | ID_SSIZET, // ssize_t |
| 85 | ID_SIZET, // size_t |
| 86 | ID_SPTRDF, // signed ptrdiff_t |
| 87 | ID_PTRDIF, // ptrdiff_t |
| 88 | |
| 89 | // floating type values: |
| 90 | ID_INF, // infinity |
| 91 | ID_NAN, // not a number |
| 92 | ID_DOUBLE, // double |
| 93 | ID_NEGDBL, // negative double |
| 94 | ID_LNGDBL, // long double |
| 95 | ID_NEGLNG // negative long double |
| 96 | }; |
| 97 | |
| 98 | BOOST_CONSTEXPR const bool g_bf = false; |
| 99 | BOOST_CONSTEXPR const bool g_bt = true; |
| 100 | BOOST_CONSTEXPR const uint64_t g_z = 0; |
| 101 | BOOST_CONSTEXPR const char g_by = 0x60; |
| 102 | BOOST_CONSTEXPR const unsigned char g_uby = 0xA0; |
| 103 | BOOST_CONSTEXPR const char g_c = 0x58; |
| 104 | BOOST_CONSTEXPR const wint_t g_wc = L'X'; // 'X', but wide |
| 105 | BOOST_CONSTEXPR const char * g_s = " string"; |
| 106 | BOOST_CONSTEXPR const wchar_t * g_ws = L"widestr"; |
| 107 | BOOST_CONSTEXPR const short g_h = numeric_limits<short>::min() + 12345; |
| 108 | BOOST_CONSTEXPR const unsigned short g_uh = numeric_limits<unsigned short>::max() - 12345; |
| 109 | BOOST_CONSTEXPR const int g_i = numeric_limits<int>::max() - 12345; |
| 110 | BOOST_CONSTEXPR const unsigned int g_ui = numeric_limits<unsigned int>::max() - 12345; |
| 111 | BOOST_CONSTEXPR const long g_l = numeric_limits<long>::max() - 12345; |
| 112 | BOOST_CONSTEXPR const unsigned long g_ul = numeric_limits<unsigned long>::max() - 12345; |
| 113 | BOOST_CONSTEXPR const int64_t g_ll = numeric_limits<int64_t>::max() - 12345; |
| 114 | BOOST_CONSTEXPR const uint64_t g_ull = numeric_limits<uint64_t>::max() - 12345; |
| 115 | BOOST_CONSTEXPR const intmax_t g_max = numeric_limits<intmax_t>::max() - 12345; |
| 116 | BOOST_CONSTEXPR const size_t g_sst = numeric_limits<size_t>::min() - 12345; |
| 117 | BOOST_CONSTEXPR const size_t g_st = numeric_limits<size_t>::max() - 12345; |
| 118 | BOOST_CONSTEXPR const ptrdiff_t g_pt = numeric_limits<ptrdiff_t>::max() - 12345; |
| 119 | BOOST_CONSTEXPR const double g_db = 1234567.891234f; |
| 120 | BOOST_CONSTEXPR const double g_ndb = -1234567.891234f; |
| 121 | BOOST_CONSTEXPR const long double g_ldb = 6543211234567.891234l; |
| 122 | BOOST_CONSTEXPR const long double g_nld = -6543211234567.891234l; |
| 123 | #if defined(INFINITY) |
| 124 | BOOST_CONSTEXPR const double g_inf = INFINITY; |
| 125 | #endif |
| 126 | #if defined(NAN) |
| 127 | BOOST_CONSTEXPR const double g_nan = NAN; |
| 128 | #endif |
| 129 | |
| 130 | boost::array<const char *, 12> length_modifier = { { "hh", "h", "", "l", "ll", "j", "z", "L", "w", "I", "I32", "I64" } }; |
| 131 | boost::array<const char *, 6> format_flags = { { "", "-", "+", " ", "#", "0" } }; |
| 132 | boost::array<const char *, 6> minimum_width = { { "", "1", "2", "5", "10", "20" } }; // TODO: , "*" } }; |
| 133 | boost::array<const char *, 7> precision = { { "", ".", ".0", ".2", ".5", ".10", ".20" } }; // TODO: , ".*" } }; |
| 134 | |
| 135 | struct interop_row |
| 136 | { |
| 137 | char conversion_specifier; |
| 138 | interop_datatype datatype[12]; |
| 139 | }; |
| 140 | |
| 141 | // Each row represents a conversion specifier which is indicated in the first column |
| 142 | // The subsequent columns are argument type specifiers for that conversion specifier |
| 143 | // The data in the cell is the value to pass into snprintf and format to see what comes out |
| 144 | |
| 145 | interop_row interop_matrix[] = { |
| 146 | // |----------------------------------- ISO C99 ---------------------------------------| |-------------- Microsoft --------------| |
| 147 | // spc, hh , h , (none) , l , ll , j , z , L , w , I , I32 , I64 |
| 148 | { 'c', { ID_UNDEF , ID_UNDEF , ID_CHAR , ID_WCHAR , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_WCHAR , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 149 | { 's', { ID_UNDEF , ID_UNDEF , ID_STR , ID_WSTR , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_WSTR , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 150 | |
| 151 | { 'd', { ID_BYTE , ID_SHORT , ID_INT , ID_LONG , ID_LLONG , ID_INTMAX, ID_SSIZET, ID_UNDEF , ID_UNDEF , ID_SPTRDF, ID_INT , ID_LLONG } }, |
| 152 | { 'd', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 153 | { 'd', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 154 | { 'i', { ID_BYTE , ID_SHORT , ID_INT , ID_LONG , ID_LLONG , ID_INTMAX, ID_SSIZET, ID_UNDEF , ID_UNDEF , ID_SPTRDF, ID_INT , ID_LLONG } }, |
| 155 | { 'i', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 156 | { 'i', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 157 | |
| 158 | { 'o', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 159 | { 'o', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 160 | { 'x', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 161 | { 'x', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 162 | { 'X', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 163 | { 'X', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 164 | { 'u', { ID_UBYTE , ID_USHORT, ID_UINT , ID_ULONG , ID_ULLONG, ID_INTMAX, ID_SIZET , ID_UNDEF , ID_UNDEF , ID_PTRDIF, ID_UINT , ID_ULLONG} }, |
| 165 | { 'u', { ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_ZERO } }, |
| 166 | |
| 167 | { 'f', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 168 | { 'f', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 169 | { 'f', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 170 | { 'f', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 171 | { 'f', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 172 | { 'F', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 173 | { 'F', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 174 | { 'F', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 175 | { 'F', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 176 | { 'F', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 177 | { 'e', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 178 | { 'e', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 179 | { 'e', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 180 | { 'e', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 181 | { 'e', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 182 | { 'E', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 183 | { 'E', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 184 | { 'E', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 185 | { 'E', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 186 | { 'E', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 187 | { 'a', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 188 | { 'a', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 189 | { 'a', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 190 | { 'a', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 191 | { 'a', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 192 | { 'A', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 193 | { 'A', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 194 | { 'A', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 195 | { 'A', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 196 | { 'A', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 197 | { 'g', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 198 | { 'g', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 199 | { 'g', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 200 | { 'g', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 201 | { 'g', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 202 | { 'G', { ID_UNDEF , ID_UNDEF , ID_DOUBLE, ID_DOUBLE, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_LNGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 203 | { 'G', { ID_UNDEF , ID_UNDEF , ID_NEGDBL, ID_NEGDBL, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NEGLNG, ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 204 | { 'G', { ID_UNDEF , ID_UNDEF , ID_INF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_INF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 205 | { 'G', { ID_UNDEF , ID_UNDEF , ID_NAN , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_NAN , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 206 | { 'G', { ID_UNDEF , ID_UNDEF , ID_ZERO , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_ZERO , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 207 | |
| 208 | // boolalpha - not supported in snprintf per ISO C99 but is by boost::format so... |
| 209 | { 'b', { ID_UNDEF , ID_UNDEF , ID_BOOLF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 210 | { 'b', { ID_UNDEF , ID_UNDEF , ID_BOOLT , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 211 | |
| 212 | // this is the terminator for conversion specifier loops: |
| 213 | { 0 , { ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF , ID_UNDEF } }, |
| 214 | }; |
| 215 | |
| 216 | std::string call_snprintf(const std::string& fmtStr, interop_datatype type) |
| 217 | { |
| 218 | // enough space to hold any value in this test |
| 219 | char buf[BUFSIZ]; |
| 220 | int len = 0; |
| 221 | |
| 222 | switch (type) |
| 223 | { |
| 224 | case ID_ZERO: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_z ); break; |
| 225 | case ID_BOOLF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bf ); break; |
| 226 | case ID_BOOLT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bt ); break; |
| 227 | case ID_BYTE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_by ); break; |
| 228 | case ID_UBYTE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uby); break; |
| 229 | case ID_CHAR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_c ); break; |
| 230 | case ID_WCHAR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_wc ); break; |
| 231 | case ID_STR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_s ); break; |
| 232 | case ID_WSTR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ws ); break; |
| 233 | case ID_SHORT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_h ); break; |
| 234 | case ID_USHORT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uh ); break; |
| 235 | case ID_INT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_i ); break; |
| 236 | case ID_UINT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ui ); break; |
| 237 | case ID_LONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_l ); break; |
| 238 | case ID_ULONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ul ); break; |
| 239 | case ID_LLONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ll ); break; |
| 240 | case ID_ULLONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ull); break; |
| 241 | case ID_INTMAX: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_max); break; |
| 242 | case ID_SSIZET: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_sst); break; |
| 243 | case ID_SIZET: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_st ); break; |
| 244 | case ID_SPTRDF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break; |
| 245 | case ID_PTRDIF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break; |
| 246 | #if defined(INFINITY) |
| 247 | case ID_INF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_inf); break; |
| 248 | #endif |
| 249 | #if defined(NAN) |
| 250 | case ID_NAN: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_nan); break; |
| 251 | #endif |
| 252 | case ID_DOUBLE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_db ); break; |
| 253 | case ID_NEGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ndb); break; |
| 254 | case ID_LNGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ldb); break; |
| 255 | case ID_NEGLNG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_nld); break; |
| 256 | default: throw logic_error("unhandled type in call_snprintf"); |
| 257 | } |
| 258 | |
| 259 | if (len < 0) |
| 260 | { |
| 261 | throw logic_error("snprintf length 0"); |
| 262 | } |
| 263 | |
| 264 | return std::string(buf, len); |
| 265 | } |
| 266 | |
| 267 | std::string call_format(const std::string& fmtStr, interop_datatype type) |
| 268 | { |
| 269 | switch (type) |
| 270 | { |
| 271 | case ID_ZERO: return ::boost::str(::boost::format(fmtStr) % g_z ); |
| 272 | case ID_BOOLF: return ::boost::str(::boost::format(fmtStr) % g_bf ); |
| 273 | case ID_BOOLT: return ::boost::str(::boost::format(fmtStr) % g_bt ); |
| 274 | case ID_BYTE: return ::boost::str(::boost::format(fmtStr) % g_by ); |
| 275 | case ID_UBYTE: return ::boost::str(::boost::format(fmtStr) % g_uby); |
| 276 | case ID_CHAR: return ::boost::str(::boost::format(fmtStr) % g_c ); |
| 277 | case ID_WCHAR: return ::boost::str(::boost::format(fmtStr) % g_wc ); |
| 278 | case ID_STR: return ::boost::str(::boost::format(fmtStr) % g_s ); |
| 279 | case ID_WSTR: return ::boost::str(::boost::format(fmtStr) % g_ws ); |
| 280 | case ID_SHORT: return ::boost::str(::boost::format(fmtStr) % g_h ); |
| 281 | case ID_USHORT: return ::boost::str(::boost::format(fmtStr) % g_uh ); |
| 282 | case ID_INT: return ::boost::str(::boost::format(fmtStr) % g_i ); |
| 283 | case ID_UINT: return ::boost::str(::boost::format(fmtStr) % g_ui ); |
| 284 | case ID_LONG: return ::boost::str(::boost::format(fmtStr) % g_l ); |
| 285 | case ID_ULONG: return ::boost::str(::boost::format(fmtStr) % g_ul ); |
| 286 | case ID_LLONG: return ::boost::str(::boost::format(fmtStr) % g_ll ); |
| 287 | case ID_ULLONG: return ::boost::str(::boost::format(fmtStr) % g_ull); |
| 288 | case ID_INTMAX: return ::boost::str(::boost::format(fmtStr) % g_max); |
| 289 | case ID_SSIZET: return ::boost::str(::boost::format(fmtStr) % g_sst); |
| 290 | case ID_SIZET: return ::boost::str(::boost::format(fmtStr) % g_st ); |
| 291 | case ID_SPTRDF: return ::boost::str(::boost::format(fmtStr) % g_pt ); |
| 292 | case ID_PTRDIF: return ::boost::str(::boost::format(fmtStr) % g_pt ); |
| 293 | #if defined(INFINITY) |
| 294 | case ID_INF: return ::boost::str(::boost::format(fmtStr) % g_inf); |
| 295 | #endif |
| 296 | #if defined(NAN) |
| 297 | case ID_NAN: return ::boost::str(::boost::format(fmtStr) % g_nan); |
| 298 | #endif |
| 299 | case ID_DOUBLE: return ::boost::str(::boost::format(fmtStr) % g_db ); |
| 300 | case ID_NEGDBL: return ::boost::str(::boost::format(fmtStr) % g_ndb); |
| 301 | case ID_LNGDBL: return ::boost::str(::boost::format(fmtStr) % g_ldb); |
| 302 | case ID_NEGLNG: return ::boost::str(::boost::format(fmtStr) % g_nld); |
| 303 | default: throw logic_error("unhandled type in call_format"); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | po::variables_map g_args; |
| 308 | ofstream g_os; |
| 309 | |
| 310 | void |
| 311 | write_header() |
| 312 | { |
| 313 | if (g_args.count("snprintf")) |
| 314 | { |
| 315 | #if BOOST_LIB_C_GNU |
| 316 | g_os << "# glibc.version = " << BOOST_VERSION_NUMBER_MAJOR(BOOST_LIB_C_GNU) << "." |
| 317 | << BOOST_VERSION_NUMBER_MINOR(BOOST_LIB_C_GNU) << "." |
| 318 | << BOOST_VERSION_NUMBER_PATCH(BOOST_LIB_C_GNU) |
| 319 | << endl; |
| 320 | #elif BOOST_COMP_MSVC |
| 321 | g_os << "# msvc.version = " << BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) << "." |
| 322 | << BOOST_VERSION_NUMBER_MINOR(BOOST_COMP_MSVC) << "." |
| 323 | << BOOST_VERSION_NUMBER_PATCH(BOOST_COMP_MSVC) |
| 324 | << endl; |
| 325 | #else |
| 326 | g_os << "# libc.version = unknown" << endl; |
| 327 | #endif |
| 328 | } |
| 329 | else |
| 330 | { |
| 331 | g_os << "# boost.version = " << BOOST_VERSION / 100000 << "." // major version |
| 332 | << BOOST_VERSION / 100 % 1000 << "." // minor version |
| 333 | << BOOST_VERSION % 100 // patch level |
| 334 | << endl; |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | void |
| 339 | log(const std::string& spec, bool ok, const std::string& result) |
| 340 | { |
| 341 | boost::io::ios_all_saver saver(g_os); |
| 342 | g_os << setw(20) << right << spec << "\t" |
| 343 | << (ok ? "OK " : "ERR") << "\t" << "\"" << result << "\"" << endl; |
| 344 | } |
| 345 | |
| 346 | void cell(std::size_t nrow, std::size_t ncol) |
| 347 | { |
| 348 | const interop_row& row(interop_matrix[nrow]); |
| 349 | |
| 350 | const interop_datatype& dataType(row.datatype[ncol]); |
| 351 | if (dataType == ID_UNDEF || dataType == ID_NOTSUP) |
| 352 | { |
| 353 | return; |
| 354 | } |
| 355 | |
| 356 | #if !defined(INFINITY) |
| 357 | if (dataType == ID_INF) |
| 358 | { |
| 359 | return; |
| 360 | } |
| 361 | #endif |
| 362 | |
| 363 | #if !defined(NAN) |
| 364 | if (dataType == ID_NAN) |
| 365 | { |
| 366 | return; |
| 367 | } |
| 368 | #endif |
| 369 | |
| 370 | // TODO: every combination of format flags - right now we do only one |
| 371 | for (std::size_t ffi = 0; ffi < format_flags.size(); ++ffi) |
| 372 | { |
| 373 | for (std::size_t mwi = 0; mwi < minimum_width.size(); ++mwi) |
| 374 | { |
| 375 | for (std::size_t pri = 0; pri < precision.size(); ++pri) |
| 376 | { |
| 377 | // Make the format string |
| 378 | std::stringstream fss; |
| 379 | fss << '%'; |
| 380 | fss << format_flags[ffi]; |
| 381 | fss << minimum_width[mwi]; |
| 382 | fss << precision[pri]; |
| 383 | fss << length_modifier[ncol]; |
| 384 | fss << row.conversion_specifier; |
| 385 | std::string fmtStr = fss.str(); |
| 386 | |
| 387 | try |
| 388 | { |
| 389 | std::string result = g_args.count("snprintf") ? |
| 390 | call_snprintf(fmtStr, dataType) : |
| 391 | call_format (fmtStr, dataType) ; |
| 392 | log(fmtStr, true, result); |
| 393 | } |
| 394 | catch (const std::exception& ex) |
| 395 | { |
| 396 | log(fmtStr, false, ex.what()); |
| 397 | } |
| 398 | } |
| 399 | } |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | void |
| 404 | matrix() |
| 405 | { |
| 406 | for (std::size_t row = 0; interop_matrix[row].conversion_specifier != 0x00; ++row) |
| 407 | { |
| 408 | for (std::size_t col = 0; col < length_modifier.size(); ++col) |
| 409 | { |
| 410 | cell(row, col); |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | void |
| 416 | write_pctpct() |
| 417 | { |
| 418 | if (g_args.count("snprintf")) |
| 419 | { |
| 420 | char buf[BUFSIZ]; |
| 421 | int len = SNPRINTF(buf, BUFSIZ, "%%"); |
| 422 | log("%%", len == 1, len == 1 ? buf : "snprintf length != 1"); |
| 423 | } |
| 424 | else |
| 425 | { |
| 426 | try |
| 427 | { |
| 428 | log("%%", true, ::boost::format("%%").str()); |
| 429 | } |
| 430 | catch (std::exception& ex) |
| 431 | { |
| 432 | log("%%", false, ex.what()); |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | void |
| 438 | generate() |
| 439 | { |
| 440 | string genpath = g_args["generate"].as<string>(); |
| 441 | g_os.open(genpath.c_str(), ios::out | ios::trunc); |
| 442 | write_header(); |
| 443 | write_pctpct(); |
| 444 | matrix(); |
| 445 | g_os.close(); |
| 446 | } |
| 447 | |
| 448 | } // matrix |
| 449 | |
| 450 | /////////////////////////////////////////////////////////////////////////////// |
| 451 | // main entry point |
| 452 | int |
| 453 | main(int argc, char *argv[]) |
| 454 | { |
| 455 | using matrix::g_args; |
| 456 | |
| 457 | po::options_description desc("Allowed options"); |
| 458 | desc.add_options() |
| 459 | ("generate,g", po::value<string>()->required(), "generate output filename") |
| 460 | ("help,h", "produce help message") |
| 461 | ("snprintf,s", "use snprintf instead of boost::format") |
| 462 | ; |
| 463 | |
| 464 | po::store(po::command_line_parser(argc, argv).options(desc).run(), g_args); |
| 465 | po::notify(g_args); |
| 466 | |
| 467 | if (g_args.count("help")) { |
| 468 | cout << "Usage: format_matrix [options]\n"; |
| 469 | cout << desc; |
| 470 | return 0; |
| 471 | } |
| 472 | |
| 473 | matrix::generate(); |
| 474 | |
| 475 | return 0; |
| 476 | } |