@@ -11,14 +11,15 @@ Author: Daniel Kroening, kroening@kroening.com
1111
1212#include " printf_formatter.h"
1313
14- #include < sstream>
15-
1614#include < util/c_types.h>
15+ #include < util/expr_util.h>
1716#include < util/format_constant.h>
1817#include < util/pointer_expr.h>
1918#include < util/simplify_expr.h>
2019#include < util/std_expr.h>
2120
21+ #include < sstream>
22+
2223const exprt printf_formattert::make_type (
2324 const exprt &src, const typet &dest)
2425{
@@ -66,6 +67,8 @@ void printf_formattert::process_format(std::ostream &out)
6667 format_constant.min_width =0 ;
6768 format_constant.zero_padding =false ;
6869
70+ std::string length_modifier;
71+
6972 char ch=next ();
7073
7174 if (ch==' 0' ) // leading zeros
@@ -94,6 +97,56 @@ void printf_formattert::process_format(std::ostream &out)
9497 }
9598 }
9699
100+ switch (ch)
101+ {
102+ case ' h' :
103+ ch = next ();
104+ if (ch == ' h' )
105+ {
106+ length_modifier = " hh" ;
107+ ch = next ();
108+ }
109+ else
110+ {
111+ length_modifier = " h" ;
112+ }
113+ break ;
114+
115+ case ' l' :
116+ ch = next ();
117+ if (ch == ' l' )
118+ {
119+ length_modifier = " ll" ;
120+ ch = next ();
121+ }
122+ else
123+ {
124+ length_modifier = " l" ;
125+ }
126+ break ;
127+
128+ case ' q' :
129+ ch = next ();
130+ length_modifier = " ll" ;
131+ break ;
132+
133+ case ' L' :
134+ case ' j' :
135+ case ' z' :
136+ case ' t' :
137+ length_modifier = ch;
138+ ch = next ();
139+ break ;
140+
141+ case ' Z' :
142+ ch = next ();
143+ length_modifier = " z" ;
144+ break ;
145+
146+ default :
147+ break ;
148+ }
149+
97150 switch (ch)
98151 {
99152 case ' %' :
@@ -105,17 +158,23 @@ void printf_formattert::process_format(std::ostream &out)
105158 format_constant.style =format_spect::stylet::SCIENTIFIC;
106159 if (next_operand==operands.end ())
107160 break ;
108- out << format_constant (
109- make_type (*(next_operand++), double_type ()));
161+ if (length_modifier == " L" )
162+ out << format_constant (make_type (*(next_operand++), long_double_type ()));
163+ else
164+ out << format_constant (make_type (*(next_operand++), double_type ()));
110165 break ;
111166
167+ case ' a' : // TODO: hexadecimal output
168+ case ' A' : // TODO: hexadecimal output
112169 case ' f' :
113170 case ' F' :
114171 format_constant.style =format_spect::stylet::DECIMAL;
115172 if (next_operand==operands.end ())
116173 break ;
117- out << format_constant (
118- make_type (*(next_operand++), double_type ()));
174+ if (length_modifier == " L" )
175+ out << format_constant (make_type (*(next_operand++), long_double_type ()));
176+ else
177+ out << format_constant (make_type (*(next_operand++), double_type ()));
119178 break ;
120179
121180 case ' g' :
@@ -125,58 +184,130 @@ void printf_formattert::process_format(std::ostream &out)
125184 format_constant.precision =1 ;
126185 if (next_operand==operands.end ())
127186 break ;
128- out << format_constant (
129- make_type (*(next_operand++), double_type ()));
187+ if (length_modifier == " L" )
188+ out << format_constant (make_type (*(next_operand++), long_double_type ()));
189+ else
190+ out << format_constant (make_type (*(next_operand++), double_type ()));
130191 break ;
131192
193+ case ' S' :
194+ length_modifier = ' l' ;
132195 case ' s' :
133196 {
134197 if (next_operand==operands.end ())
135198 break ;
136199 // this is the address of a string
137200 const exprt &op=*(next_operand++);
138201 if (
139- op.id () == ID_address_of &&
140- to_address_of_expr (op).object ().id () == ID_index &&
141- to_index_expr (to_address_of_expr (op).object ()).array ().id () ==
142- ID_string_constant)
202+ auto pointer_constant =
203+ expr_try_dynamic_cast<annotated_pointer_constant_exprt>(op))
143204 {
144- out << format_constant (
145- to_index_expr (to_address_of_expr (op).object ()).array ());
205+ if (
206+ auto address_of = expr_try_dynamic_cast<address_of_exprt>(
207+ skip_typecast (pointer_constant->symbolic_pointer ())))
208+ {
209+ if (address_of->object ().id () == ID_string_constant)
210+ {
211+ out << format_constant (address_of->object ());
212+ }
213+ else if (
214+ auto index_expr =
215+ expr_try_dynamic_cast<index_exprt>(address_of->object ()))
216+ {
217+ if (
218+ index_expr->index ().is_zero () &&
219+ index_expr->array ().id () == ID_string_constant)
220+ {
221+ out << format_constant (index_expr->array ());
222+ }
223+ }
224+ }
146225 }
147226 }
148227 break ;
149228
150229 case ' d' :
230+ case ' i' :
231+ {
151232 if (next_operand==operands.end ())
152233 break ;
153- out << format_constant (
154- make_type (*(next_operand++), signed_int_type ()));
234+ typet conversion_type;
235+ if (length_modifier == " hh" )
236+ conversion_type = signed_char_type ();
237+ else if (length_modifier == " h" )
238+ conversion_type = signed_short_int_type ();
239+ else if (length_modifier == " l" )
240+ conversion_type = signed_long_int_type ();
241+ else if (length_modifier == " ll" )
242+ conversion_type = signed_long_long_int_type ();
243+ else if (length_modifier == " j" ) // intmax_t
244+ conversion_type = signed_long_long_int_type ();
245+ else if (length_modifier == " z" )
246+ conversion_type = signed_size_type ();
247+ else if (length_modifier == " t" )
248+ conversion_type = pointer_diff_type ();
249+ else
250+ conversion_type = signed_int_type ();
251+ out << format_constant (make_type (*(next_operand++), conversion_type));
252+ }
155253 break ;
156254
157- case ' D' :
158- if (next_operand==operands.end ())
159- break ;
160- out << format_constant (
161- make_type (*(next_operand++), signed_long_int_type ()));
255+ case ' o' : // TODO: octal output
256+ case ' x' : // TODO: hexadecimal output
257+ case ' X' : // TODO: hexadecimal output
258+ case ' u' :
259+ {
260+ if (next_operand == operands.end ())
261+ break ;
262+ typet conversion_type;
263+ if (length_modifier == " hh" )
264+ conversion_type = unsigned_char_type ();
265+ else if (length_modifier == " h" )
266+ conversion_type = unsigned_short_int_type ();
267+ else if (length_modifier == " l" )
268+ conversion_type = unsigned_long_int_type ();
269+ else if (length_modifier == " ll" )
270+ conversion_type = unsigned_long_long_int_type ();
271+ else if (length_modifier == " j" ) // intmax_t
272+ conversion_type = unsigned_long_long_int_type ();
273+ else if (length_modifier == " z" )
274+ conversion_type = size_type ();
275+ else if (length_modifier == " t" )
276+ conversion_type = pointer_diff_type ();
277+ else
278+ conversion_type = unsigned_int_type ();
279+ out << format_constant (make_type (*(next_operand++), conversion_type));
280+ }
162281 break ;
163282
164- case ' u' :
165- if (next_operand==operands.end ())
283+ case ' C' :
284+ length_modifier = ' l' ;
285+ case ' c' :
286+ if (next_operand == operands.end ())
287+ break ;
288+ if (length_modifier == " l" )
289+ out << format_constant (make_type (*(next_operand++), wchar_t_type ()));
290+ else
291+ out << format_constant (
292+ make_type (*(next_operand++), unsigned_char_type ()));
166293 break ;
167- out << format_constant (
168- make_type (*(next_operand++), unsigned_int_type ()));
169- break ;
170294
171- case ' U' :
172- if (next_operand==operands.end ())
295+ case ' p' :
296+ // TODO: hexadecimal output
297+ out << format_constant (make_type (*(next_operand++), size_type ()));
173298 break ;
174- out << format_constant (
175- make_type (*(next_operand++), unsigned_long_int_type ()));
176- break ;
177299
178- default :
179- out << ' %' << ch;
300+ case ' n' :
301+ if (next_operand == operands.end ())
302+ break ;
303+ // printf would store the number of characters written so far in the
304+ // object pointed to by this operand. We do not implement this side-effect
305+ // here, and just skip one operand.
306+ ++next_operand;
307+ break ;
308+
309+ default :
310+ out << ' %' << ch;
180311 }
181312}
182313
0 commit comments