// ------------------------------------------------------------------------------ // format_matrix.cpp : tool to check for regressions between boost format // releases and compare format specification handling // ------------------------------------------------------------------------------ // Copyright 2017 - 2019 James E. King, III. Use, modification, and distribution // are subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/format for library home page // ------------------------------------------------------------------------------ // reference (ISO C99) : http://en.cppreference.com/w/cpp/io/c/fprintf // reference (Java) : http://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html // reference (Microsoft) : https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions // reference (POSIX 2008): http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html #include #include #include #include #include #include #include #include #include #include #include #if BOOST_COMP_MSVC && BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) >= 19 #include // wint_t #endif #include #include #include #include #include #include #include #include #define SNPRINTF snprintf #if BOOST_COMP_MSVC && BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) < 19 #undef SNPRINTF #define SNPRINTF _snprintf #endif namespace fs = boost::filesystem; namespace po = boost::program_options; using namespace std; namespace matrix { enum interop_datatype { // special types: ID_UNDEF, // undefined behavior according to the spec, so combination is not tested ID_NOTSUP, // behavior is not supported and therefore not tested currently // boolean type values: ID_BOOLF, // false ID_BOOLT, // true // string type values: ID_CHAR, // single signed character ID_UCHAR, // single unsigned character ID_WCHAR, // single wide character ID_STR, // C style string ID_WSTR, // C style wide string // integer type values: ID_ZERO, // zero value ID_BYTE, // int8_t ID_UBYTE, // uint8_t ID_SHORT, // signed short ID_USHORT, // unsigned short ID_INT, // signed integer ID_UINT, // unsigned integer ID_LONG, // signed long ID_ULONG, // unsigned long ID_LLONG, // signed long long ID_ULLONG, // unsigned long long ID_INTMAX, // intmax_t ID_SSIZET, // ssize_t ID_SIZET, // size_t ID_SPTRDF, // signed ptrdiff_t ID_PTRDIF, // ptrdiff_t // floating type values: ID_INF, // infinity ID_NAN, // not a number ID_DOUBLE, // double ID_NEGDBL, // negative double ID_LNGDBL, // long double ID_NEGLNG // negative long double }; BOOST_CONSTEXPR const bool g_bf = false; BOOST_CONSTEXPR const bool g_bt = true; BOOST_CONSTEXPR const uint64_t g_z = 0; BOOST_CONSTEXPR const char g_by = 0x60; BOOST_CONSTEXPR const unsigned char g_uby = 0xA0; BOOST_CONSTEXPR const char g_c = 0x58; BOOST_CONSTEXPR const wint_t g_wc = L'X'; // 'X', but wide BOOST_CONSTEXPR const char * g_s = " string"; BOOST_CONSTEXPR const wchar_t * g_ws = L"widestr"; BOOST_CONSTEXPR const short g_h = numeric_limits::min() + 12345; BOOST_CONSTEXPR const unsigned short g_uh = numeric_limits::max() - 12345; BOOST_CONSTEXPR const int g_i = numeric_limits::max() - 12345; BOOST_CONSTEXPR const unsigned int g_ui = numeric_limits::max() - 12345; BOOST_CONSTEXPR const long g_l = numeric_limits::max() - 12345; BOOST_CONSTEXPR const unsigned long g_ul = numeric_limits::max() - 12345; BOOST_CONSTEXPR const int64_t g_ll = numeric_limits::max() - 12345; BOOST_CONSTEXPR const uint64_t g_ull = numeric_limits::max() - 12345; BOOST_CONSTEXPR const intmax_t g_max = numeric_limits::max() - 12345; BOOST_CONSTEXPR const size_t g_sst = numeric_limits::min() - 12345; BOOST_CONSTEXPR const size_t g_st = numeric_limits::max() - 12345; BOOST_CONSTEXPR const ptrdiff_t g_pt = numeric_limits::max() - 12345; BOOST_CONSTEXPR const double g_db = 1234567.891234f; BOOST_CONSTEXPR const double g_ndb = -1234567.891234f; BOOST_CONSTEXPR const long double g_ldb = 6543211234567.891234l; BOOST_CONSTEXPR const long double g_nld = -6543211234567.891234l; boost::array length_modifier = { { "hh", "h", "", "l", "ll", "j", "z", "L", "w", "I", "I32", "I64" } }; boost::array format_flags = { { "", "-", "+", " ", "#", "0" } }; boost::array minimum_width = { { "", "1", "2", "5", "10", "20" } }; // TODO: , "*" } }; boost::array precision = { { "", ".", ".0", ".2", ".5", ".10", ".20" } }; // TODO: , ".*" } }; struct interop_row { char conversion_specifier; interop_datatype datatype[12]; }; // Each row represents a conversion specifier which is indicated in the first column // The subsequent columns are argument type specifiers for that conversion specifier // The data in the cell is the value to pass into snprintf and format to see what comes out interop_row interop_matrix[] = { // |----------------------------------- ISO C99 ---------------------------------------| |-------------- Microsoft --------------| // spc, hh , h , (none) , l , ll , j , z , L , w , I , I32 , I64 { '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 } }, { '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 } }, { '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 } }, { '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} }, { '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 } }, { '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 } }, { '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} }, { '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 } }, { '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} }, { '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 } }, { '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} }, { '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 } }, { '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} }, { '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 } }, { '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} }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, { '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 } }, // boolalpha - not supported in snprintf per ISO C99 but is by boost::format so... { '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 } }, { '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 } }, // this is the terminator for conversion specifier loops: { 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 } }, }; std::string call_snprintf(const std::string& fmtStr, interop_datatype type) { // enough space to hold any value in this test char buf[BUFSIZ]; int len = 0; switch (type) { case ID_ZERO: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_z ); break; case ID_BOOLF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bf ); break; case ID_BOOLT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bt ); break; case ID_BYTE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_by ); break; case ID_UBYTE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uby); break; case ID_CHAR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_c ); break; case ID_WCHAR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_wc ); break; case ID_STR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_s ); break; case ID_WSTR: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ws ); break; case ID_SHORT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_h ); break; case ID_USHORT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uh ); break; case ID_INT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_i ); break; case ID_UINT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ui ); break; case ID_LONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_l ); break; case ID_ULONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ul ); break; case ID_LLONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ll ); break; case ID_ULLONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ull); break; case ID_INTMAX: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_max); break; case ID_SSIZET: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_sst); break; case ID_SIZET: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_st ); break; case ID_SPTRDF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break; case ID_PTRDIF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break; #if defined(INFINITY) case ID_INF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), INFINITY); break; #endif #if defined(NAN) case ID_NAN: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), NAN); break; #endif case ID_DOUBLE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_db ); break; case ID_NEGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ndb); break; case ID_LNGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ldb); break; case ID_NEGLNG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_nld); break; default: throw logic_error("unhandled type in call_snprintf"); } if (len < 0) { throw logic_error("snprintf length 0"); } return std::string(buf, len); } std::string call_format(const std::string& fmtStr, interop_datatype type) { switch (type) { case ID_ZERO: return ::boost::str(::boost::format(fmtStr) % g_z ); case ID_BOOLF: return ::boost::str(::boost::format(fmtStr) % g_bf ); case ID_BOOLT: return ::boost::str(::boost::format(fmtStr) % g_bt ); case ID_BYTE: return ::boost::str(::boost::format(fmtStr) % g_by ); case ID_UBYTE: return ::boost::str(::boost::format(fmtStr) % g_uby); case ID_CHAR: return ::boost::str(::boost::format(fmtStr) % g_c ); case ID_WCHAR: return ::boost::str(::boost::format(fmtStr) % g_wc ); case ID_STR: return ::boost::str(::boost::format(fmtStr) % g_s ); case ID_WSTR: return ::boost::str(::boost::format(fmtStr) % g_ws ); case ID_SHORT: return ::boost::str(::boost::format(fmtStr) % g_h ); case ID_USHORT: return ::boost::str(::boost::format(fmtStr) % g_uh ); case ID_INT: return ::boost::str(::boost::format(fmtStr) % g_i ); case ID_UINT: return ::boost::str(::boost::format(fmtStr) % g_ui ); case ID_LONG: return ::boost::str(::boost::format(fmtStr) % g_l ); case ID_ULONG: return ::boost::str(::boost::format(fmtStr) % g_ul ); case ID_LLONG: return ::boost::str(::boost::format(fmtStr) % g_ll ); case ID_ULLONG: return ::boost::str(::boost::format(fmtStr) % g_ull); case ID_INTMAX: return ::boost::str(::boost::format(fmtStr) % g_max); case ID_SSIZET: return ::boost::str(::boost::format(fmtStr) % g_sst); case ID_SIZET: return ::boost::str(::boost::format(fmtStr) % g_st ); case ID_SPTRDF: return ::boost::str(::boost::format(fmtStr) % g_pt ); case ID_PTRDIF: return ::boost::str(::boost::format(fmtStr) % g_pt ); #if defined(INFINITY) case ID_INF: return ::boost::str(::boost::format(fmtStr) % INFINITY); #endif #if defined(NAN) case ID_NAN: return ::boost::str(::boost::format(fmtStr) % NAN); #endif case ID_DOUBLE: return ::boost::str(::boost::format(fmtStr) % g_db ); case ID_NEGDBL: return ::boost::str(::boost::format(fmtStr) % g_ndb); case ID_LNGDBL: return ::boost::str(::boost::format(fmtStr) % g_ldb); case ID_NEGLNG: return ::boost::str(::boost::format(fmtStr) % g_nld); default: throw logic_error("unhandled type in call_format"); } } po::variables_map g_args; ofstream g_os; void write_header() { if (g_args.count("snprintf")) { #if BOOST_LIB_C_GNU g_os << "# glibc.version = " << BOOST_VERSION_NUMBER_MAJOR(BOOST_LIB_C_GNU) << "." << BOOST_VERSION_NUMBER_MINOR(BOOST_LIB_C_GNU) << "." << BOOST_VERSION_NUMBER_PATCH(BOOST_LIB_C_GNU) << endl; #elif BOOST_COMP_MSVC g_os << "# msvc.version = " << BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) << "." << BOOST_VERSION_NUMBER_MINOR(BOOST_COMP_MSVC) << "." << BOOST_VERSION_NUMBER_PATCH(BOOST_COMP_MSVC) << endl; #else g_os << "# libc.version = unknown" << endl; #endif } else { g_os << "# boost.version = " << BOOST_VERSION / 100000 << "." // major version << BOOST_VERSION / 100 % 1000 << "." // minor version << BOOST_VERSION % 100 // patch level << endl; } } void log(const std::string& spec, bool ok, const std::string& result) { boost::io::ios_all_saver saver(g_os); g_os << setw(20) << right << spec << "\t" << (ok ? "OK " : "ERR") << "\t" << "\"" << result << "\"" << endl; } void cell(std::size_t nrow, std::size_t ncol) { const interop_row& row(interop_matrix[nrow]); const interop_datatype& dataType(row.datatype[ncol]); if (dataType == ID_UNDEF || dataType == ID_NOTSUP) { return; } #if !defined(INFINITY) if (dataType == ID_INF) { return; } #endif #if !defined(NAN) if (dataType == ID_NAN) { return; } #endif // TODO: every combination of format flags - right now we do only one for (std::size_t ffi = 0; ffi < format_flags.size(); ++ffi) { for (std::size_t mwi = 0; mwi < minimum_width.size(); ++mwi) { for (std::size_t pri = 0; pri < precision.size(); ++pri) { // Make the format string std::stringstream fss; fss << '%'; fss << format_flags[ffi]; fss << minimum_width[mwi]; fss << precision[pri]; fss << length_modifier[ncol]; fss << row.conversion_specifier; std::string fmtStr = fss.str(); try { std::string result = g_args.count("snprintf") ? call_snprintf(fmtStr, dataType) : call_format (fmtStr, dataType) ; log(fmtStr, true, result); } catch (const std::exception& ex) { log(fmtStr, false, ex.what()); } } } } } void matrix() { for (std::size_t row = 0; interop_matrix[row].conversion_specifier != 0x00; ++row) { for (std::size_t col = 0; col < length_modifier.size(); ++col) { cell(row, col); } } } void write_pctpct() { if (g_args.count("snprintf")) { char buf[BUFSIZ]; int len = SNPRINTF(buf, BUFSIZ, "%%"); log("%%", len == 1, len == 1 ? buf : "snprintf length != 1"); } else { try { log("%%", true, ::boost::format("%%").str()); } catch (std::exception& ex) { log("%%", false, ex.what()); } } } void generate() { string genpath = g_args["generate"].as(); g_os.open(genpath.c_str(), ios::out | ios::trunc); write_header(); write_pctpct(); matrix(); g_os.close(); } } // matrix /////////////////////////////////////////////////////////////////////////////// // main entry point int main(int argc, char *argv[]) { using matrix::g_args; po::options_description desc("Allowed options"); desc.add_options() ("generate,g", po::value()->required(), "generate output filename") ("help,h", "produce help message") ("snprintf,s", "use snprintf instead of boost::format") ; po::store(po::command_line_parser(argc, argv).options(desc).run(), g_args); po::notify(g_args); if (g_args.count("help")) { cout << "Usage: format_matrix [options]\n"; cout << desc; return 0; } matrix::generate(); return 0; }