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 - 2019 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 
124 boost::array<const char *, 12> length_modifier = { { "hh", "h", "", "l", "ll", "j", "z", "L", "w", "I", "I32", "I64" } };
125 boost::array<const char *, 6>  format_flags    = { { "", "-", "+", " ", "#", "0" } };
126 boost::array<const char *, 6>  minimum_width   = { { "", "1", "2", "5", "10", "20" } };           // TODO: , "*" } };
127 boost::array<const char *, 7>  precision       = { { "", ".", ".0", ".2", ".5", ".10", ".20" } }; // TODO: , ".*" } };
128 
129 struct interop_row
130 {
131     char conversion_specifier;
132     interop_datatype datatype[12];
133 };
134 
135 // Each row represents a conversion specifier which is indicated in the first column
136 // The subsequent columns are argument type specifiers for that conversion specifier
137 // The data in the cell is the value to pass into snprintf and format to see what comes out
138 
139 interop_row interop_matrix[] = {
140     //         |----------------------------------- ISO C99 ---------------------------------------|   |-------------- Microsoft --------------|
141     //  spc,   hh       , h        , (none)   , l        , ll       , j        , z        , L        , w        , I        , I32      , I64
142       { '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 } },
143       { '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 } },
144 
145       { '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 } },
146       { '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} },
147       { '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  } },
148       { '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 } },
149       { '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} },
150       { '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  } },
151 
152       { '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} },
153       { '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  } },
154       { '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} },
155       { '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  } },
156       { '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} },
157       { '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  } },
158       { '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} },
159       { '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  } },
160 
161       { '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 } },
162       { '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 } },
163       { '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 } },
164       { '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 } },
165       { '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 } },
166       { '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 } },
167       { '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 } },
168       { '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 } },
169       { '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 } },
170       { '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 } },
171       { '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 } },
172       { '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 } },
173       { '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 } },
174       { '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 } },
175       { '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 } },
176       { '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 } },
177       { '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 } },
178       { '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 } },
179       { '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 } },
180       { '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 } },
181       { '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 } },
182       { '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 } },
183       { '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 } },
184       { '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 } },
185       { '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 } },
186       { '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 } },
187       { '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 } },
188       { '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 } },
189       { '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 } },
190       { '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 } },
191       { '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 } },
192       { '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 } },
193       { '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 } },
194       { '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 } },
195       { '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 } },
196       { '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 } },
197       { '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 } },
198       { '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 } },
199       { '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 } },
200       { '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 } },
201 
202     // boolalpha - not supported in snprintf per ISO C99 but is by boost::format so...
203       { '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 } },
204       { '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 } },
205 
206     // this is the terminator for conversion specifier loops:
207       {  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 } },
208 };
209 
call_snprintf(const std::string & fmtStr,interop_datatype type)210 std::string call_snprintf(const std::string& fmtStr, interop_datatype type)
211 {
212     // enough space to hold any value in this test
213     char buf[BUFSIZ];
214     int len = 0;
215 
216     switch (type)
217     {
218         case ID_ZERO:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_z  ); break;
219         case ID_BOOLF:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bf ); break;
220         case ID_BOOLT:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_bt ); break;
221         case ID_BYTE:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_by ); break;
222         case ID_UBYTE:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uby); break;
223         case ID_CHAR:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_c  ); break;
224         case ID_WCHAR:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_wc ); break;
225         case ID_STR:    len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_s  ); break;
226         case ID_WSTR:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ws ); break;
227         case ID_SHORT:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_h  ); break;
228         case ID_USHORT: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_uh ); break;
229         case ID_INT:    len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_i  ); break;
230         case ID_UINT:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ui ); break;
231         case ID_LONG:   len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_l  ); break;
232         case ID_ULONG:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ul ); break;
233         case ID_LLONG:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ll ); break;
234         case ID_ULLONG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ull); break;
235         case ID_INTMAX: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_max); break;
236         case ID_SSIZET: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_sst); break;
237         case ID_SIZET:  len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_st ); break;
238         case ID_SPTRDF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break;
239         case ID_PTRDIF: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_pt ); break;
240 #if defined(INFINITY)
241         case ID_INF:    len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), INFINITY); break;
242 #endif
243 #if defined(NAN)
244         case ID_NAN:    len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), NAN);   break;
245 #endif
246         case ID_DOUBLE: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_db ); break;
247         case ID_NEGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ndb); break;
248         case ID_LNGDBL: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_ldb); break;
249         case ID_NEGLNG: len = SNPRINTF(buf, BUFSIZ, fmtStr.c_str(), g_nld); break;
250         default: throw logic_error("unhandled type in call_snprintf");
251     }
252 
253     if (len < 0)
254     {
255         throw logic_error("snprintf length 0");
256     }
257 
258     return std::string(buf, len);
259 }
260 
call_format(const std::string & fmtStr,interop_datatype type)261 std::string call_format(const std::string& fmtStr, interop_datatype type)
262 {
263     switch (type)
264     {
265         case ID_ZERO:   return ::boost::str(::boost::format(fmtStr) % g_z  );
266         case ID_BOOLF:  return ::boost::str(::boost::format(fmtStr) % g_bf );
267         case ID_BOOLT:  return ::boost::str(::boost::format(fmtStr) % g_bt );
268         case ID_BYTE:   return ::boost::str(::boost::format(fmtStr) % g_by );
269         case ID_UBYTE:  return ::boost::str(::boost::format(fmtStr) % g_uby);
270         case ID_CHAR:   return ::boost::str(::boost::format(fmtStr) % g_c  );
271         case ID_WCHAR:  return ::boost::str(::boost::format(fmtStr) % g_wc );
272         case ID_STR:    return ::boost::str(::boost::format(fmtStr) % g_s  );
273         case ID_WSTR:   return ::boost::str(::boost::format(fmtStr) % g_ws );
274         case ID_SHORT:  return ::boost::str(::boost::format(fmtStr) % g_h  );
275         case ID_USHORT: return ::boost::str(::boost::format(fmtStr) % g_uh );
276         case ID_INT:    return ::boost::str(::boost::format(fmtStr) % g_i  );
277         case ID_UINT:   return ::boost::str(::boost::format(fmtStr) % g_ui );
278         case ID_LONG:   return ::boost::str(::boost::format(fmtStr) % g_l  );
279         case ID_ULONG:  return ::boost::str(::boost::format(fmtStr) % g_ul );
280         case ID_LLONG:  return ::boost::str(::boost::format(fmtStr) % g_ll );
281         case ID_ULLONG: return ::boost::str(::boost::format(fmtStr) % g_ull);
282         case ID_INTMAX: return ::boost::str(::boost::format(fmtStr) % g_max);
283         case ID_SSIZET: return ::boost::str(::boost::format(fmtStr) % g_sst);
284         case ID_SIZET:  return ::boost::str(::boost::format(fmtStr) % g_st );
285         case ID_SPTRDF: return ::boost::str(::boost::format(fmtStr) % g_pt );
286         case ID_PTRDIF: return ::boost::str(::boost::format(fmtStr) % g_pt );
287 #if defined(INFINITY)
288         case ID_INF:    return ::boost::str(::boost::format(fmtStr) % INFINITY);
289 #endif
290 #if defined(NAN)
291         case ID_NAN:    return ::boost::str(::boost::format(fmtStr) % NAN);
292 #endif
293         case ID_DOUBLE: return ::boost::str(::boost::format(fmtStr) % g_db );
294         case ID_NEGDBL: return ::boost::str(::boost::format(fmtStr) % g_ndb);
295         case ID_LNGDBL: return ::boost::str(::boost::format(fmtStr) % g_ldb);
296         case ID_NEGLNG: return ::boost::str(::boost::format(fmtStr) % g_nld);
297         default: throw logic_error("unhandled type in call_format");
298     }
299 }
300 
301 po::variables_map g_args;
302 ofstream g_os;
303 
304 void
write_header()305 write_header()
306 {
307     if (g_args.count("snprintf"))
308     {
309 #if BOOST_LIB_C_GNU
310         g_os << "# glibc.version = " << BOOST_VERSION_NUMBER_MAJOR(BOOST_LIB_C_GNU) << "."
311                                      << BOOST_VERSION_NUMBER_MINOR(BOOST_LIB_C_GNU) << "."
312                                      << BOOST_VERSION_NUMBER_PATCH(BOOST_LIB_C_GNU)
313                                      << endl;
314 #elif BOOST_COMP_MSVC
315         g_os << "# msvc.version = "  << BOOST_VERSION_NUMBER_MAJOR(BOOST_COMP_MSVC) << "."
316                                      << BOOST_VERSION_NUMBER_MINOR(BOOST_COMP_MSVC) << "."
317                                      << BOOST_VERSION_NUMBER_PATCH(BOOST_COMP_MSVC)
318                                      << endl;
319 #else
320         g_os << "# libc.version = unknown" << endl;
321 #endif
322     }
323     else
324     {
325         g_os << "# boost.version = " << BOOST_VERSION / 100000 << "."      // major version
326                                      << BOOST_VERSION / 100 % 1000 << "."  // minor version
327                                      << BOOST_VERSION % 100                // patch level
328                                      << endl;
329     }
330 }
331 
332 void
log(const std::string & spec,bool ok,const std::string & result)333 log(const std::string& spec, bool ok, const std::string& result)
334 {
335     boost::io::ios_all_saver saver(g_os);
336     g_os << setw(20) << right << spec << "\t"
337          << (ok ? "OK " : "ERR") << "\t" << "\"" << result << "\"" << endl;
338 }
339 
cell(std::size_t nrow,std::size_t ncol)340 void cell(std::size_t nrow, std::size_t ncol)
341 {
342     const interop_row& row(interop_matrix[nrow]);
343 
344     const interop_datatype& dataType(row.datatype[ncol]);
345     if (dataType == ID_UNDEF || dataType == ID_NOTSUP)
346     {
347         return;
348     }
349 
350 #if !defined(INFINITY)
351     if (dataType == ID_INF)
352     {
353         return;
354     }
355 #endif
356 
357 #if !defined(NAN)
358     if (dataType == ID_NAN)
359     {
360         return;
361     }
362 #endif
363 
364     // TODO: every combination of format flags - right now we do only one
365     for (std::size_t ffi = 0; ffi < format_flags.size(); ++ffi)
366     {
367         for (std::size_t mwi = 0; mwi < minimum_width.size(); ++mwi)
368         {
369             for (std::size_t pri = 0; pri < precision.size(); ++pri)
370             {
371                 // Make the format string
372                 std::stringstream fss;
373                 fss << '%';
374                 fss << format_flags[ffi];
375                 fss << minimum_width[mwi];
376                 fss << precision[pri];
377                 fss << length_modifier[ncol];
378                 fss << row.conversion_specifier;
379                 std::string fmtStr = fss.str();
380 
381                 try
382                 {
383                     std::string result = g_args.count("snprintf") ?
384                                             call_snprintf(fmtStr, dataType) :
385                                             call_format  (fmtStr, dataType) ;
386                     log(fmtStr, true, result);
387                 }
388                 catch (const std::exception& ex)
389                 {
390                     log(fmtStr, false, ex.what());
391                 }
392             }
393         }
394     }
395 }
396 
397 void
matrix()398 matrix()
399 {
400     for (std::size_t row = 0; interop_matrix[row].conversion_specifier != 0x00; ++row)
401     {
402         for (std::size_t col = 0; col < length_modifier.size(); ++col)
403         {
404             cell(row, col);
405         }
406     }
407 }
408 
409 void
write_pctpct()410 write_pctpct()
411 {
412     if (g_args.count("snprintf"))
413     {
414         char buf[BUFSIZ];
415         int len = SNPRINTF(buf, BUFSIZ, "%%");
416         log("%%", len == 1, len == 1 ? buf : "snprintf length != 1");
417     }
418     else
419     {
420         try
421         {
422             log("%%", true, ::boost::format("%%").str());
423         }
424         catch (std::exception& ex)
425         {
426             log("%%", false, ex.what());
427         }
428     }
429 }
430 
431 void
generate()432 generate()
433 {
434     string genpath = g_args["generate"].as<string>();
435     g_os.open(genpath.c_str(), ios::out | ios::trunc);
436     write_header();
437     write_pctpct();
438     matrix();
439     g_os.close();
440 }
441 
442 } // matrix
443 
444 ///////////////////////////////////////////////////////////////////////////////
445 //  main entry point
446 int
main(int argc,char * argv[])447 main(int argc, char *argv[])
448 {
449     using matrix::g_args;
450 
451     po::options_description desc("Allowed options");
452     desc.add_options()
453         ("generate,g", po::value<string>()->required(), "generate output filename")
454         ("help,h", "produce help message")
455         ("snprintf,s", "use snprintf instead of boost::format")
456         ;
457 
458     po::store(po::command_line_parser(argc, argv).options(desc).run(), g_args);
459     po::notify(g_args);
460 
461     if (g_args.count("help")) {
462         cout << "Usage: format_matrix [options]\n";
463         cout << desc;
464         return 0;
465     }
466 
467     matrix::generate();
468 
469     return 0;
470 }
471