format_matrix.cpp 25 KB

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