GDB (xrefs)
format.c
Go to the documentation of this file.
1 /* Parse a printf-style format string.
2 
3  Copyright (C) 1986-2015 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 
23 struct format_piece *
24 parse_format_string (const char **arg)
25 {
26  const char *s;
27  char *f, *string;
28  const char *prev_start;
29  const char *percent_loc;
30  char *sub_start, *current_substring;
31  struct format_piece *pieces;
32  int next_frag;
33  int max_pieces;
34  enum argclass this_argclass;
35 
36  s = *arg;
37 
38  /* Parse the format-control string and copy it into the string STRING,
39  processing some kinds of escape sequence. */
40 
41  f = string = (char *) alloca (strlen (s) + 1);
42 
43  while (*s != '"' && *s != '\0')
44  {
45  int c = *s++;
46  switch (c)
47  {
48  case '\0':
49  continue;
50 
51  case '\\':
52  switch (c = *s++)
53  {
54  case '\\':
55  *f++ = '\\';
56  break;
57  case 'a':
58  *f++ = '\a';
59  break;
60  case 'b':
61  *f++ = '\b';
62  break;
63  case 'f':
64  *f++ = '\f';
65  break;
66  case 'n':
67  *f++ = '\n';
68  break;
69  case 'r':
70  *f++ = '\r';
71  break;
72  case 't':
73  *f++ = '\t';
74  break;
75  case 'v':
76  *f++ = '\v';
77  break;
78  case '"':
79  *f++ = '"';
80  break;
81  default:
82  /* ??? TODO: handle other escape sequences. */
83  error (_("Unrecognized escape character \\%c in format string."),
84  c);
85  }
86  break;
87 
88  default:
89  *f++ = c;
90  }
91  }
92 
93  /* Terminate our escape-processed copy. */
94  *f++ = '\0';
95 
96  /* Whether the format string ended with double-quote or zero, we're
97  done with it; it's up to callers to complain about syntax. */
98  *arg = s;
99 
100  /* Need extra space for the '\0's. Doubling the size is sufficient. */
101 
102  current_substring = xmalloc (strlen (string) * 2 + 1000);
103 
104  max_pieces = strlen (string) + 2;
105 
106  pieces = (struct format_piece *)
107  xmalloc (max_pieces * sizeof (struct format_piece));
108 
109  next_frag = 0;
110 
111  /* Now scan the string for %-specs and see what kinds of args they want.
112  argclass classifies the %-specs so we can give printf-type functions
113  something of the right size. */
114 
115  f = string;
116  prev_start = string;
117  while (*f)
118  if (*f++ == '%')
119  {
120  int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
121  int seen_space = 0, seen_plus = 0;
122  int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
123  int seen_big_d = 0, seen_double_big_d = 0;
124  int bad = 0;
125 
126  /* Skip over "%%", it will become part of a literal piece. */
127  if (*f == '%')
128  {
129  f++;
130  continue;
131  }
132 
133  sub_start = current_substring;
134 
135  strncpy (current_substring, prev_start, f - 1 - prev_start);
136  current_substring += f - 1 - prev_start;
137  *current_substring++ = '\0';
138 
139  pieces[next_frag].string = sub_start;
140  pieces[next_frag].argclass = literal_piece;
141  next_frag++;
142 
143  percent_loc = f - 1;
144 
145  /* Check the validity of the format specifier, and work
146  out what argument it expects. We only accept C89
147  format strings, with the exception of long long (which
148  we autoconf for). */
149 
150  /* The first part of a format specifier is a set of flag
151  characters. */
152  while (*f != '\0' && strchr ("0-+ #", *f))
153  {
154  if (*f == '#')
155  seen_hash = 1;
156  else if (*f == '0')
157  seen_zero = 1;
158  else if (*f == ' ')
159  seen_space = 1;
160  else if (*f == '+')
161  seen_plus = 1;
162  f++;
163  }
164 
165  /* The next part of a format specifier is a width. */
166  while (*f != '\0' && strchr ("0123456789", *f))
167  f++;
168 
169  /* The next part of a format specifier is a precision. */
170  if (*f == '.')
171  {
172  seen_prec = 1;
173  f++;
174  while (*f != '\0' && strchr ("0123456789", *f))
175  f++;
176  }
177 
178  /* The next part of a format specifier is a length modifier. */
179  if (*f == 'h')
180  {
181  seen_h = 1;
182  f++;
183  }
184  else if (*f == 'l')
185  {
186  f++;
187  lcount++;
188  if (*f == 'l')
189  {
190  f++;
191  lcount++;
192  }
193  }
194  else if (*f == 'L')
195  {
196  seen_big_l = 1;
197  f++;
198  }
199  /* Decimal32 modifier. */
200  else if (*f == 'H')
201  {
202  seen_big_h = 1;
203  f++;
204  }
205  /* Decimal64 and Decimal128 modifiers. */
206  else if (*f == 'D')
207  {
208  f++;
209 
210  /* Check for a Decimal128. */
211  if (*f == 'D')
212  {
213  f++;
214  seen_double_big_d = 1;
215  }
216  else
217  seen_big_d = 1;
218  }
219 
220  switch (*f)
221  {
222  case 'u':
223  if (seen_hash)
224  bad = 1;
225  /* FALLTHROUGH */
226 
227  case 'o':
228  case 'x':
229  case 'X':
230  if (seen_space || seen_plus)
231  bad = 1;
232  /* FALLTHROUGH */
233 
234  case 'd':
235  case 'i':
236  if (lcount == 0)
237  this_argclass = int_arg;
238  else if (lcount == 1)
239  this_argclass = long_arg;
240  else
241  this_argclass = long_long_arg;
242 
243  if (seen_big_l)
244  bad = 1;
245  break;
246 
247  case 'c':
248  this_argclass = lcount == 0 ? int_arg : wide_char_arg;
249  if (lcount > 1 || seen_h || seen_big_l)
250  bad = 1;
251  if (seen_prec || seen_zero || seen_space || seen_plus)
252  bad = 1;
253  break;
254 
255  case 'p':
256  this_argclass = ptr_arg;
257  if (lcount || seen_h || seen_big_l)
258  bad = 1;
259  if (seen_prec)
260  bad = 1;
261  if (seen_hash || seen_zero || seen_space || seen_plus)
262  bad = 1;
263  break;
264 
265  case 's':
266  this_argclass = lcount == 0 ? string_arg : wide_string_arg;
267  if (lcount > 1 || seen_h || seen_big_l)
268  bad = 1;
269  if (seen_zero || seen_space || seen_plus)
270  bad = 1;
271  break;
272 
273  case 'e':
274  case 'f':
275  case 'g':
276  case 'E':
277  case 'G':
278  if (seen_big_h || seen_big_d || seen_double_big_d)
279  this_argclass = decfloat_arg;
280  else if (seen_big_l)
281  this_argclass = long_double_arg;
282  else
283  this_argclass = double_arg;
284 
285  if (lcount || seen_h)
286  bad = 1;
287  break;
288 
289  case '*':
290  error (_("`*' not supported for precision or width in printf"));
291 
292  case 'n':
293  error (_("Format specifier `n' not supported in printf"));
294 
295  case '\0':
296  error (_("Incomplete format specifier at end of format string"));
297 
298  default:
299  error (_("Unrecognized format specifier '%c' in printf"), *f);
300  }
301 
302  if (bad)
303  error (_("Inappropriate modifiers to "
304  "format specifier '%c' in printf"),
305  *f);
306 
307  f++;
308 
309  sub_start = current_substring;
310 
311  if (lcount > 1 && USE_PRINTF_I64)
312  {
313  /* Windows' printf does support long long, but not the usual way.
314  Convert %lld to %I64d. */
315  int length_before_ll = f - percent_loc - 1 - lcount;
316 
317  strncpy (current_substring, percent_loc, length_before_ll);
318  strcpy (current_substring + length_before_ll, "I64");
319  current_substring[length_before_ll + 3] =
320  percent_loc[length_before_ll + lcount];
321  current_substring += length_before_ll + 4;
322  }
323  else if (this_argclass == wide_string_arg
324  || this_argclass == wide_char_arg)
325  {
326  /* Convert %ls or %lc to %s. */
327  int length_before_ls = f - percent_loc - 2;
328 
329  strncpy (current_substring, percent_loc, length_before_ls);
330  strcpy (current_substring + length_before_ls, "s");
331  current_substring += length_before_ls + 2;
332  }
333  else
334  {
335  strncpy (current_substring, percent_loc, f - percent_loc);
336  current_substring += f - percent_loc;
337  }
338 
339  *current_substring++ = '\0';
340 
341  prev_start = f;
342 
343  pieces[next_frag].string = sub_start;
344  pieces[next_frag].argclass = this_argclass;
345  next_frag++;
346  }
347 
348  /* Record the remainder of the string. */
349 
350  sub_start = current_substring;
351 
352  strncpy (current_substring, prev_start, f - prev_start);
353  current_substring += f - prev_start;
354  *current_substring++ = '\0';
355 
356  pieces[next_frag].string = sub_start;
357  pieces[next_frag].argclass = literal_piece;
358  next_frag++;
359 
360  /* Record an end-of-array marker. */
361 
362  pieces[next_frag].string = NULL;
363  pieces[next_frag].argclass = literal_piece;
364 
365  return pieces;
366 }
367 
368 void
370 {
371  if (!pieces)
372  return;
373 
374  /* We happen to know that all the string pieces are in the block
375  pointed to by the first string piece. */
376  if (pieces[0].string)
377  xfree (pieces[0].string);
378 
379  xfree (pieces);
380 }
381 
382 void
384 {
385  void **location = ptr;
386 
387  if (location == NULL)
388  return;
389 
390  if (*location != NULL)
391  {
392  free_format_pieces (*location);
393  *location = NULL;
394  }
395 }
396 
const char * string
Definition: signals.c:50
void xfree(void *)
Definition: common-utils.c:97
argclass
Definition: format.h:33
char * string
Definition: format.h:47
#define _(String)
Definition: gdb_locale.h:40
#define USE_PRINTF_I64
Definition: format.h:24
void free_format_pieces_cleanup(void *ptr)
Definition: format.c:383
struct format_piece * parse_format_string(const char **arg)
Definition: format.c:24
Definition: format.h:36
enum argclass argclass
Definition: format.h:48
void * xmalloc(YYSIZE_T)
void free_format_pieces(struct format_piece *pieces)
Definition: format.c:369
void error(const char *fmt,...)
Definition: errors.c:38
Definition: format.h:36