ld: =fillexp different behaviors for hexidecimal literal
[binutils-gdb.git] / gdbsupport / format.cc
blob6e5a3cb6603d9506f8c54760d408eb742195f625
1 /* Parse a printf-style format string.
3 Copyright (C) 1986-2023 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"
21 #include "format.h"
23 format_pieces::format_pieces (const char **arg, bool gdb_extensions,
24 bool value_extension)
26 const char *s;
27 const char *string;
28 const char *prev_start;
29 const char *percent_loc;
30 char *sub_start, *current_substring;
31 enum argclass this_argclass;
33 s = *arg;
35 if (gdb_extensions)
37 string = *arg;
38 *arg += strlen (*arg);
40 else
42 /* Parse the format-control string and copy it into the string STRING,
43 processing some kinds of escape sequence. */
45 char *f = (char *) alloca (strlen (s) + 1);
46 string = f;
48 while (*s != '"' && *s != '\0')
50 int c = *s++;
51 switch (c)
53 case '\0':
54 continue;
56 case '\\':
57 switch (c = *s++)
59 case '\\':
60 *f++ = '\\';
61 break;
62 case 'a':
63 *f++ = '\a';
64 break;
65 case 'b':
66 *f++ = '\b';
67 break;
68 case 'e':
69 *f++ = '\e';
70 break;
71 case 'f':
72 *f++ = '\f';
73 break;
74 case 'n':
75 *f++ = '\n';
76 break;
77 case 'r':
78 *f++ = '\r';
79 break;
80 case 't':
81 *f++ = '\t';
82 break;
83 case 'v':
84 *f++ = '\v';
85 break;
86 case '"':
87 *f++ = '"';
88 break;
89 default:
90 /* ??? TODO: handle other escape sequences. */
91 error (_("Unrecognized escape character \\%c in format string."),
92 c);
94 break;
96 default:
97 *f++ = c;
101 /* Terminate our escape-processed copy. */
102 *f++ = '\0';
104 /* Whether the format string ended with double-quote or zero, we're
105 done with it; it's up to callers to complain about syntax. */
106 *arg = s;
109 /* Need extra space for the '\0's. Doubling the size is sufficient. */
111 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
112 m_storage.reset (current_substring);
114 /* Now scan the string for %-specs and see what kinds of args they want.
115 argclass classifies the %-specs so we can give printf-type functions
116 something of the right size. */
118 const char *f = string;
119 prev_start = string;
120 while (*f)
121 if (*f++ == '%')
123 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
124 int seen_space = 0, seen_plus = 0;
125 int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
126 int seen_big_d = 0, seen_double_big_d = 0;
127 int seen_size_t = 0;
128 int bad = 0;
129 int n_int_args = 0;
130 bool seen_i64 = false;
132 /* Skip over "%%", it will become part of a literal piece. */
133 if (*f == '%')
135 f++;
136 continue;
139 sub_start = current_substring;
141 strncpy (current_substring, prev_start, f - 1 - prev_start);
142 current_substring += f - 1 - prev_start;
143 *current_substring++ = '\0';
145 if (*sub_start != '\0')
146 m_pieces.emplace_back (sub_start, literal_piece, 0);
148 percent_loc = f - 1;
150 /* Check the validity of the format specifier, and work
151 out what argument it expects. We only accept C89
152 format strings, with the exception of long long (which
153 we autoconf for). */
155 /* The first part of a format specifier is a set of flag
156 characters. */
157 while (*f != '\0' && strchr ("0-+ #", *f))
159 if (*f == '#')
160 seen_hash = 1;
161 else if (*f == '0')
162 seen_zero = 1;
163 else if (*f == ' ')
164 seen_space = 1;
165 else if (*f == '+')
166 seen_plus = 1;
167 f++;
170 /* The next part of a format specifier is a width. */
171 if (gdb_extensions && *f == '*')
173 ++f;
174 ++n_int_args;
176 else
178 while (*f != '\0' && strchr ("0123456789", *f))
179 f++;
182 /* The next part of a format specifier is a precision. */
183 if (*f == '.')
185 seen_prec = 1;
186 f++;
187 if (gdb_extensions && *f == '*')
189 ++f;
190 ++n_int_args;
192 else
194 while (*f != '\0' && strchr ("0123456789", *f))
195 f++;
199 /* The next part of a format specifier is a length modifier. */
200 switch (*f)
202 case 'h':
203 seen_h = 1;
204 f++;
205 break;
206 case 'l':
207 f++;
208 lcount++;
209 if (*f == 'l')
211 f++;
212 lcount++;
214 break;
215 case 'L':
216 seen_big_l = 1;
217 f++;
218 break;
219 case 'H':
220 /* Decimal32 modifier. */
221 seen_big_h = 1;
222 f++;
223 break;
224 case 'D':
225 /* Decimal64 and Decimal128 modifiers. */
226 f++;
228 /* Check for a Decimal128. */
229 if (*f == 'D')
231 f++;
232 seen_double_big_d = 1;
234 else
235 seen_big_d = 1;
236 break;
237 case 'z':
238 /* For size_t or ssize_t. */
239 seen_size_t = 1;
240 f++;
241 break;
242 case 'I':
243 /* Support the Windows '%I64' extension, because an
244 earlier call to format_pieces might have converted %lld
245 to %I64d. */
246 if (f[1] == '6' && f[2] == '4')
248 f += 3;
249 lcount = 2;
250 seen_i64 = true;
252 break;
255 switch (*f)
257 case 'u':
258 if (seen_hash)
259 bad = 1;
260 /* FALLTHROUGH */
262 case 'o':
263 case 'x':
264 case 'X':
265 if (seen_space || seen_plus)
266 bad = 1;
267 /* FALLTHROUGH */
269 case 'd':
270 case 'i':
271 if (seen_size_t)
272 this_argclass = size_t_arg;
273 else if (lcount == 0)
274 this_argclass = int_arg;
275 else if (lcount == 1)
276 this_argclass = long_arg;
277 else
278 this_argclass = long_long_arg;
280 if (seen_big_l)
281 bad = 1;
282 break;
284 case 'c':
285 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
286 if (lcount > 1 || seen_h || seen_big_l)
287 bad = 1;
288 if (seen_prec || seen_zero || seen_space || seen_plus)
289 bad = 1;
290 break;
292 case 'p':
293 this_argclass = ptr_arg;
294 if (lcount || seen_h || seen_big_l)
295 bad = 1;
296 if (seen_prec)
297 bad = 1;
298 if (seen_hash || seen_zero || seen_space || seen_plus)
299 bad = 1;
301 if (gdb_extensions)
303 switch (f[1])
305 case 's':
306 case 'F':
307 case '[':
308 case ']':
309 f++;
310 break;
314 break;
316 case 's':
317 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
318 if (lcount > 1 || seen_h || seen_big_l)
319 bad = 1;
320 if (seen_zero || seen_space || seen_plus)
321 bad = 1;
322 break;
324 case 'e':
325 case 'f':
326 case 'g':
327 case 'E':
328 case 'G':
329 if (seen_double_big_d)
330 this_argclass = dec128float_arg;
331 else if (seen_big_d)
332 this_argclass = dec64float_arg;
333 else if (seen_big_h)
334 this_argclass = dec32float_arg;
335 else if (seen_big_l)
336 this_argclass = long_double_arg;
337 else
338 this_argclass = double_arg;
340 if (lcount || seen_h)
341 bad = 1;
342 break;
344 case 'V':
345 if (!value_extension)
346 error (_("Unrecognized format specifier '%c' in printf"), *f);
348 if (lcount > 1 || seen_h || seen_big_h || seen_big_h
349 || seen_big_d || seen_double_big_d || seen_size_t
350 || seen_prec || seen_zero || seen_space || seen_plus)
351 bad = 1;
353 this_argclass = value_arg;
355 if (f[1] == '[')
357 /* Move F forward to the next ']' character if such a
358 character exists, otherwise leave F unchanged. */
359 const char *tmp = strchr (f, ']');
360 if (tmp != nullptr)
361 f = tmp;
363 break;
365 case '*':
366 error (_("`*' not supported for precision or width in printf"));
368 case 'n':
369 error (_("Format specifier `n' not supported in printf"));
371 case '\0':
372 error (_("Incomplete format specifier at end of format string"));
374 default:
375 error (_("Unrecognized format specifier '%c' in printf"), *f);
378 if (bad)
379 error (_("Inappropriate modifiers to "
380 "format specifier '%c' in printf"),
381 *f);
383 f++;
385 sub_start = current_substring;
387 if (lcount > 1 && !seen_i64 && USE_PRINTF_I64)
389 /* Windows' printf does support long long, but not the usual way.
390 Convert %lld to %I64d. */
391 int length_before_ll = f - percent_loc - 1 - lcount;
393 strncpy (current_substring, percent_loc, length_before_ll);
394 strcpy (current_substring + length_before_ll, "I64");
395 current_substring[length_before_ll + 3] =
396 percent_loc[length_before_ll + lcount];
397 current_substring += length_before_ll + 4;
399 else if (this_argclass == wide_string_arg
400 || this_argclass == wide_char_arg)
402 /* Convert %ls or %lc to %s. */
403 int length_before_ls = f - percent_loc - 2;
405 strncpy (current_substring, percent_loc, length_before_ls);
406 strcpy (current_substring + length_before_ls, "s");
407 current_substring += length_before_ls + 2;
409 else
411 strncpy (current_substring, percent_loc, f - percent_loc);
412 current_substring += f - percent_loc;
415 *current_substring++ = '\0';
417 prev_start = f;
419 m_pieces.emplace_back (sub_start, this_argclass, n_int_args);
422 /* Record the remainder of the string. */
424 if (f > prev_start)
426 sub_start = current_substring;
428 strncpy (current_substring, prev_start, f - prev_start);
429 current_substring += f - prev_start;
430 *current_substring++ = '\0';
432 m_pieces.emplace_back (sub_start, literal_piece, 0);