GDB (xrefs)
format.c
Go to the documentation of this file.
1 /* Parse a printf-style format string.
2 
3  Copyright (C) 1986-2018 Free Software Foundation, Inc.
4 
5  This file is part of GDB.
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 
20 #include "common-defs.h"
21 #include "format.h"
22 
24 {
25  const char *s;
26  char *f, *string;
27  const char *prev_start;
28  const char *percent_loc;
29  char *sub_start, *current_substring;
30  enum argclass this_argclass;
31 
32  s = *arg;
33 
34  /* Parse the format-control string and copy it into the string STRING,
35  processing some kinds of escape sequence. */
36 
37  f = string = (char *) alloca (strlen (s) + 1);
38 
39  while (*s != '"' && *s != '\0')
40  {
41  int c = *s++;
42  switch (c)
43  {
44  case '\0':
45  continue;
46 
47  case '\\':
48  switch (c = *s++)
49  {
50  case '\\':
51  *f++ = '\\';
52  break;
53  case 'a':
54  *f++ = '\a';
55  break;
56  case 'b':
57  *f++ = '\b';
58  break;
59  case 'f':
60  *f++ = '\f';
61  break;
62  case 'n':
63  *f++ = '\n';
64  break;
65  case 'r':
66  *f++ = '\r';
67  break;
68  case 't':
69  *f++ = '\t';
70  break;
71  case 'v':
72  *f++ = '\v';
73  break;
74  case '"':
75  *f++ = '"';
76  break;
77  default:
78  /* ??? TODO: handle other escape sequences. */
79  error (_("Unrecognized escape character \\%c in format string."),
80  c);
81  }
82  break;
83 
84  default:
85  *f++ = c;
86  }
87  }
88 
89  /* Terminate our escape-processed copy. */
90  *f++ = '\0';
91 
92  /* Whether the format string ended with double-quote or zero, we're
93  done with it; it's up to callers to complain about syntax. */
94  *arg = s;
95 
96  /* Need extra space for the '\0's. Doubling the size is sufficient. */
97 
98  current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
99  m_storage.reset (current_substring);
100 
101  /* Now scan the string for %-specs and see what kinds of args they want.
102  argclass classifies the %-specs so we can give printf-type functions
103  something of the right size. */
104 
105  f = string;
106  prev_start = string;
107  while (*f)
108  if (*f++ == '%')
109  {
110  int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
111  int seen_space = 0, seen_plus = 0;
112  int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
113  int seen_big_d = 0, seen_double_big_d = 0;
114  int bad = 0;
115 
116  /* Skip over "%%", it will become part of a literal piece. */
117  if (*f == '%')
118  {
119  f++;
120  continue;
121  }
122 
123  sub_start = current_substring;
124 
125  strncpy (current_substring, prev_start, f - 1 - prev_start);
126  current_substring += f - 1 - prev_start;
127  *current_substring++ = '\0';
128 
129  m_pieces.emplace_back (sub_start, literal_piece);
130 
131  percent_loc = f - 1;
132 
133  /* Check the validity of the format specifier, and work
134  out what argument it expects. We only accept C89
135  format strings, with the exception of long long (which
136  we autoconf for). */
137 
138  /* The first part of a format specifier is a set of flag
139  characters. */
140  while (*f != '\0' && strchr ("0-+ #", *f))
141  {
142  if (*f == '#')
143  seen_hash = 1;
144  else if (*f == '0')
145  seen_zero = 1;
146  else if (*f == ' ')
147  seen_space = 1;
148  else if (*f == '+')
149  seen_plus = 1;
150  f++;
151  }
152 
153  /* The next part of a format specifier is a width. */
154  while (*f != '\0' && strchr ("0123456789", *f))
155  f++;
156 
157  /* The next part of a format specifier is a precision. */
158  if (*f == '.')
159  {
160  seen_prec = 1;
161  f++;
162  while (*f != '\0' && strchr ("0123456789", *f))
163  f++;
164  }
165 
166  /* The next part of a format specifier is a length modifier. */
167  if (*f == 'h')
168  {
169  seen_h = 1;
170  f++;
171  }
172  else if (*f == 'l')
173  {
174  f++;
175  lcount++;
176  if (*f == 'l')
177  {
178  f++;
179  lcount++;
180  }
181  }
182  else if (*f == 'L')
183  {
184  seen_big_l = 1;
185  f++;
186  }
187  /* Decimal32 modifier. */
188  else if (*f == 'H')
189  {
190  seen_big_h = 1;
191  f++;
192  }
193  /* Decimal64 and Decimal128 modifiers. */
194  else if (*f == 'D')
195  {
196  f++;
197 
198  /* Check for a Decimal128. */
199  if (*f == 'D')
200  {
201  f++;
202  seen_double_big_d = 1;
203  }
204  else
205  seen_big_d = 1;
206  }
207 
208  switch (*f)
209  {
210  case 'u':
211  if (seen_hash)
212  bad = 1;
213  /* FALLTHROUGH */
214 
215  case 'o':
216  case 'x':
217  case 'X':
218  if (seen_space || seen_plus)
219  bad = 1;
220  /* FALLTHROUGH */
221 
222  case 'd':
223  case 'i':
224  if (lcount == 0)
225  this_argclass = int_arg;
226  else if (lcount == 1)
227  this_argclass = long_arg;
228  else
229  this_argclass = long_long_arg;
230 
231  if (seen_big_l)
232  bad = 1;
233  break;
234 
235  case 'c':
236  this_argclass = lcount == 0 ? int_arg : wide_char_arg;
237  if (lcount > 1 || seen_h || seen_big_l)
238  bad = 1;
239  if (seen_prec || seen_zero || seen_space || seen_plus)
240  bad = 1;
241  break;
242 
243  case 'p':
244  this_argclass = ptr_arg;
245  if (lcount || seen_h || seen_big_l)
246  bad = 1;
247  if (seen_prec)
248  bad = 1;
249  if (seen_hash || seen_zero || seen_space || seen_plus)
250  bad = 1;
251  break;
252 
253  case 's':
254  this_argclass = lcount == 0 ? string_arg : wide_string_arg;
255  if (lcount > 1 || seen_h || seen_big_l)
256  bad = 1;
257  if (seen_zero || seen_space || seen_plus)
258  bad = 1;
259  break;
260 
261  case 'e':
262  case 'f':
263  case 'g':
264  case 'E':
265  case 'G':
266  if (seen_double_big_d)
267  this_argclass = dec128float_arg;
268  else if (seen_big_d)
269  this_argclass = dec64float_arg;
270  else if (seen_big_h)
271  this_argclass = dec32float_arg;
272  else if (seen_big_l)
273  this_argclass = long_double_arg;
274  else
275  this_argclass = double_arg;
276 
277  if (lcount || seen_h)
278  bad = 1;
279  break;
280 
281  case '*':
282  error (_("`*' not supported for precision or width in printf"));
283 
284  case 'n':
285  error (_("Format specifier `n' not supported in printf"));
286 
287  case '\0':
288  error (_("Incomplete format specifier at end of format string"));
289 
290  default:
291  error (_("Unrecognized format specifier '%c' in printf"), *f);
292  }
293 
294  if (bad)
295  error (_("Inappropriate modifiers to "
296  "format specifier '%c' in printf"),
297  *f);
298 
299  f++;
300 
301  sub_start = current_substring;
302 
303  if (lcount > 1 && USE_PRINTF_I64)
304  {
305  /* Windows' printf does support long long, but not the usual way.
306  Convert %lld to %I64d. */
307  int length_before_ll = f - percent_loc - 1 - lcount;
308 
309  strncpy (current_substring, percent_loc, length_before_ll);
310  strcpy (current_substring + length_before_ll, "I64");
311  current_substring[length_before_ll + 3] =
312  percent_loc[length_before_ll + lcount];
313  current_substring += length_before_ll + 4;
314  }
315  else if (this_argclass == wide_string_arg
316  || this_argclass == wide_char_arg)
317  {
318  /* Convert %ls or %lc to %s. */
319  int length_before_ls = f - percent_loc - 2;
320 
321  strncpy (current_substring, percent_loc, length_before_ls);
322  strcpy (current_substring + length_before_ls, "s");
323  current_substring += length_before_ls + 2;
324  }
325  else
326  {
327  strncpy (current_substring, percent_loc, f - percent_loc);
328  current_substring += f - percent_loc;
329  }
330 
331  *current_substring++ = '\0';
332 
333  prev_start = f;
334 
335  m_pieces.emplace_back (sub_start, this_argclass);
336  }
337 
338  /* Record the remainder of the string. */
339 
340  sub_start = current_substring;
341 
342  strncpy (current_substring, prev_start, f - prev_start);
343  current_substring += f - prev_start;
344  *current_substring++ = '\0';
345 
346  m_pieces.emplace_back (sub_start, literal_piece);
347 }
const char * string
Definition: signals.c:50
argclass
Definition: format.h:36
gdb::unique_xmalloc_ptr< char > m_storage
Definition: format.h:90
#define _(String)
Definition: gdb_locale.h:35
#define USE_PRINTF_I64
Definition: format.h:27
format_pieces(const char **arg)
Definition: format.c:23
Definition: format.h:39
void * xmalloc(YYSIZE_T)
void * arg
Definition: cleanups.c:43
void error(const char *fmt,...)
Definition: errors.c:38
Definition: format.h:39
std::vector< format_piece > m_pieces
Definition: format.h:89