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