CBMC
printf_formatter.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: printf Formatting
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "printf_formatter.h"
13 
14 #include <util/c_types.h>
15 #include <util/expr_util.h>
16 #include <util/format_constant.h>
17 #include <util/pointer_expr.h>
18 #include <util/simplify_expr.h>
19 #include <util/std_expr.h>
20 
21 #include <sstream>
22 
24  const exprt &src, const typet &dest)
25 {
26  if(src.type()==dest)
27  return src;
28  return simplify_expr(typecast_exprt(src, dest), ns);
29 }
30 
32  const std::string &_format,
33  const std::list<exprt> &_operands)
34 {
35  format=_format;
36  operands=_operands;
37 }
38 
39 void printf_formattert::print(std::ostream &out)
40 {
41  format_pos=0;
42  next_operand=operands.begin();
43 
44  try
45  {
46  while(!eol()) process_char(out);
47  }
48 
49  catch(const eol_exceptiont &)
50  {
51  }
52 }
53 
55 {
56  std::ostringstream stream;
57  print(stream);
58  return stream.str();
59 }
60 
61 void printf_formattert::process_format(std::ostream &out)
62 {
63  exprt tmp;
64  format_constantt format_constant;
65 
66  format_constant.precision=6;
67  format_constant.min_width=0;
68  format_constant.zero_padding=false;
69 
70  std::string length_modifier;
71 
72  char ch=next();
73 
74  if(ch=='0') // leading zeros
75  {
76  format_constant.zero_padding=true;
77  ch=next();
78  }
79 
80  while(isdigit(ch)) // width
81  {
82  format_constant.min_width*=10;
83  format_constant.min_width+=ch-'0';
84  ch=next();
85  }
86 
87  if(ch=='.') // precision
88  {
89  format_constant.precision=0;
90  ch=next();
91 
92  while(isdigit(ch))
93  {
94  format_constant.precision*=10;
95  format_constant.precision+=ch-'0';
96  ch=next();
97  }
98  }
99 
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 
150  switch(ch)
151  {
152  case '%':
153  out << ch;
154  break;
155 
156  case 'e':
157  case 'E':
158  format_constant.style=format_spect::stylet::SCIENTIFIC;
159  if(next_operand==operands.end())
160  break;
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()));
165  break;
166 
167  case 'a': // TODO: hexadecimal output
168  case 'A': // TODO: hexadecimal output
169  case 'f':
170  case 'F':
171  format_constant.style=format_spect::stylet::DECIMAL;
172  if(next_operand==operands.end())
173  break;
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()));
178  break;
179 
180  case 'g':
181  case 'G':
182  format_constant.style=format_spect::stylet::AUTOMATIC;
183  if(format_constant.precision==0)
184  format_constant.precision=1;
185  if(next_operand==operands.end())
186  break;
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()));
191  break;
192 
193  case 'S':
194  length_modifier = 'l';
195  case 's':
196  {
197  if(next_operand==operands.end())
198  break;
199  // this is the address of a string
200  const exprt &op=*(next_operand++);
201  if(
202  auto pointer_constant =
203  expr_try_dynamic_cast<annotated_pointer_constant_exprt>(op))
204  {
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  }
225  }
226  }
227  break;
228 
229  case 'd':
230  case 'i':
231  {
232  if(next_operand==operands.end())
233  break;
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  }
253  break;
254 
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  }
281  break;
282 
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(
293  break;
294 
295  case 'p':
296  // TODO: hexadecimal output
297  out << format_constant(make_type(*(next_operand++), size_type()));
298  break;
299 
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;
311  }
312 }
313 
314 void printf_formattert::process_char(std::ostream &out)
315 {
316  char ch=next();
317 
318  if(ch=='%')
319  process_format(out);
320  else
321  out << ch;
322 }
signedbv_typet signed_long_int_type()
Definition: c_types.cpp:72
signedbv_typet signed_char_type()
Definition: c_types.cpp:134
unsignedbv_typet unsigned_int_type()
Definition: c_types.cpp:36
unsignedbv_typet unsigned_long_long_int_type()
Definition: c_types.cpp:93
unsignedbv_typet unsigned_long_int_type()
Definition: c_types.cpp:86
signedbv_typet signed_int_type()
Definition: c_types.cpp:22
signedbv_typet pointer_diff_type()
Definition: c_types.cpp:220
unsignedbv_typet unsigned_char_type()
Definition: c_types.cpp:127
signedbv_typet signed_size_type()
Definition: c_types.cpp:66
signedbv_typet signed_long_long_int_type()
Definition: c_types.cpp:79
bitvector_typet wchar_t_type()
Definition: c_types.cpp:141
floatbv_typet long_double_type()
Definition: c_types.cpp:193
floatbv_typet double_type()
Definition: c_types.cpp:185
signedbv_typet signed_short_int_type()
Definition: c_types.cpp:29
unsignedbv_typet unsigned_short_int_type()
Definition: c_types.cpp:43
Base class for all expressions.
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:84
stylet style
Definition: format_spec.h:28
bool zero_padding
Definition: format_spec.h:20
unsigned precision
Definition: format_spec.h:19
unsigned min_width
Definition: format_spec.h:18
std::list< exprt > operands
const exprt make_type(const exprt &src, const typet &dest)
std::list< exprt >::const_iterator next_operand
std::string as_string()
void operator()(const std::string &format, const std::list< exprt > &_operands)
void process_format(std::ostream &out)
void print(std::ostream &out)
const namespacet & ns
void process_char(std::ostream &out)
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
int isdigit(int c)
Definition: ctype.c:24
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:219
Deprecated expression utility functions.
API to expression classes for Pointers.
printf Formatting
exprt simplify_expr(exprt src, const namespacet &ns)
API to expression classes.
#define size_type
Definition: unistd.c:347