1 /* Parse a printf-style format string.
3 Copyright (C) 1986-2016 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "common-defs.h"
24 parse_format_string (const char **arg)
28 const char *prev_start;
29 const char *percent_loc;
30 char *sub_start, *current_substring;
31 struct format_piece *pieces;
34 enum argclass this_argclass;
38 /* Parse the format-control string and copy it into the string STRING,
39 processing some kinds of escape sequence. */
41 f = string = (char *) alloca (strlen (s) + 1);
43 while (*s != '"' && *s != '\0')
82 /* ??? TODO: handle other escape sequences. */
83 error (_("Unrecognized escape character \\%c in format string."),
93 /* Terminate our escape-processed copy. */
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. */
100 /* Need extra space for the '\0's. Doubling the size is sufficient. */
102 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
104 max_pieces = strlen (string) + 2;
106 pieces = XNEWVEC (struct format_piece, max_pieces);
110 /* Now scan the string for %-specs and see what kinds of args they want.
111 argclass classifies the %-specs so we can give printf-type functions
112 something of the right size. */
119 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
120 int seen_space = 0, seen_plus = 0;
121 int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
122 int seen_big_d = 0, seen_double_big_d = 0;
125 /* Skip over "%%", it will become part of a literal piece. */
132 sub_start = current_substring;
134 strncpy (current_substring, prev_start, f - 1 - prev_start);
135 current_substring += f - 1 - prev_start;
136 *current_substring++ = '\0';
138 pieces[next_frag].string = sub_start;
139 pieces[next_frag].argclass = literal_piece;
144 /* Check the validity of the format specifier, and work
145 out what argument it expects. We only accept C89
146 format strings, with the exception of long long (which
149 /* The first part of a format specifier is a set of flag
151 while (*f != '\0' && strchr ("0-+ #", *f))
164 /* The next part of a format specifier is a width. */
165 while (*f != '\0' && strchr ("0123456789", *f))
168 /* The next part of a format specifier is a precision. */
173 while (*f != '\0' && strchr ("0123456789", *f))
177 /* The next part of a format specifier is a length modifier. */
198 /* Decimal32 modifier. */
204 /* Decimal64 and Decimal128 modifiers. */
209 /* Check for a Decimal128. */
213 seen_double_big_d = 1;
229 if (seen_space || seen_plus)
236 this_argclass = int_arg;
237 else if (lcount == 1)
238 this_argclass = long_arg;
240 this_argclass = long_long_arg;
247 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
248 if (lcount > 1 || seen_h || seen_big_l)
250 if (seen_prec || seen_zero || seen_space || seen_plus)
255 this_argclass = ptr_arg;
256 if (lcount || seen_h || seen_big_l)
260 if (seen_hash || seen_zero || seen_space || seen_plus)
265 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
266 if (lcount > 1 || seen_h || seen_big_l)
268 if (seen_zero || seen_space || seen_plus)
277 if (seen_big_h || seen_big_d || seen_double_big_d)
278 this_argclass = decfloat_arg;
280 this_argclass = long_double_arg;
282 this_argclass = double_arg;
284 if (lcount || seen_h)
289 error (_("`*' not supported for precision or width in printf"));
292 error (_("Format specifier `n' not supported in printf"));
295 error (_("Incomplete format specifier at end of format string"));
298 error (_("Unrecognized format specifier '%c' in printf"), *f);
302 error (_("Inappropriate modifiers to "
303 "format specifier '%c' in printf"),
308 sub_start = current_substring;
310 if (lcount > 1 && USE_PRINTF_I64)
312 /* Windows' printf does support long long, but not the usual way.
313 Convert %lld to %I64d. */
314 int length_before_ll = f - percent_loc - 1 - lcount;
316 strncpy (current_substring, percent_loc, length_before_ll);
317 strcpy (current_substring + length_before_ll, "I64");
318 current_substring[length_before_ll + 3] =
319 percent_loc[length_before_ll + lcount];
320 current_substring += length_before_ll + 4;
322 else if (this_argclass == wide_string_arg
323 || this_argclass == wide_char_arg)
325 /* Convert %ls or %lc to %s. */
326 int length_before_ls = f - percent_loc - 2;
328 strncpy (current_substring, percent_loc, length_before_ls);
329 strcpy (current_substring + length_before_ls, "s");
330 current_substring += length_before_ls + 2;
334 strncpy (current_substring, percent_loc, f - percent_loc);
335 current_substring += f - percent_loc;
338 *current_substring++ = '\0';
342 pieces[next_frag].string = sub_start;
343 pieces[next_frag].argclass = this_argclass;
347 /* Record the remainder of the string. */
349 sub_start = current_substring;
351 strncpy (current_substring, prev_start, f - prev_start);
352 current_substring += f - prev_start;
353 *current_substring++ = '\0';
355 pieces[next_frag].string = sub_start;
356 pieces[next_frag].argclass = literal_piece;
359 /* Record an end-of-array marker. */
361 pieces[next_frag].string = NULL;
362 pieces[next_frag].argclass = literal_piece;
368 free_format_pieces (struct format_piece *pieces)
373 /* We happen to know that all the string pieces are in the block
374 pointed to by the first string piece. */
375 if (pieces[0].string)
376 xfree (pieces[0].string);
382 free_format_pieces_cleanup (void *ptr)
384 struct format_piece **location = (struct format_piece **) ptr;
386 if (location == NULL)
389 if (*location != NULL)
391 free_format_pieces (*location);