gdb: Don't skip prologue for explicit line breakpoints in assembler
[deliverable/binutils-gdb.git] / gdb / common / 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
8e481c3b 23format_pieces::format_pieces (const char **arg)
d3ce09f5 24{
bbc13ae3
KS
25 const char *s;
26 char *f, *string;
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
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;
b17992c1
SM
59 case 'e':
60 *f++ = '\e';
61 break;
d3ce09f5
SS
62 case 'f':
63 *f++ = '\f';
64 break;
65 case 'n':
66 *f++ = '\n';
67 break;
68 case 'r':
69 *f++ = '\r';
70 break;
71 case 't':
72 *f++ = '\t';
73 break;
74 case 'v':
75 *f++ = '\v';
76 break;
77 case '"':
78 *f++ = '"';
79 break;
80 default:
81 /* ??? TODO: handle other escape sequences. */
82 error (_("Unrecognized escape character \\%c in format string."),
83 c);
84 }
85 break;
86
87 default:
88 *f++ = c;
89 }
90 }
91
92 /* Terminate our escape-processed copy. */
93 *f++ = '\0';
94
95 /* Whether the format string ended with double-quote or zero, we're
96 done with it; it's up to callers to complain about syntax. */
97 *arg = s;
98
99 /* Need extra space for the '\0's. Doubling the size is sufficient. */
100
224c3ddb 101 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
8e481c3b 102 m_storage.reset (current_substring);
d3ce09f5
SS
103
104 /* Now scan the string for %-specs and see what kinds of args they want.
105 argclass classifies the %-specs so we can give printf-type functions
106 something of the right size. */
107
108 f = string;
109 prev_start = string;
110 while (*f)
111 if (*f++ == '%')
112 {
113 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
114 int seen_space = 0, seen_plus = 0;
115 int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
116 int seen_big_d = 0, seen_double_big_d = 0;
117 int bad = 0;
118
119 /* Skip over "%%", it will become part of a literal piece. */
120 if (*f == '%')
121 {
122 f++;
123 continue;
124 }
125
126 sub_start = current_substring;
127
128 strncpy (current_substring, prev_start, f - 1 - prev_start);
129 current_substring += f - 1 - prev_start;
130 *current_substring++ = '\0';
131
8e481c3b 132 m_pieces.emplace_back (sub_start, literal_piece);
d3ce09f5
SS
133
134 percent_loc = f - 1;
135
136 /* Check the validity of the format specifier, and work
137 out what argument it expects. We only accept C89
138 format strings, with the exception of long long (which
139 we autoconf for). */
140
141 /* The first part of a format specifier is a set of flag
142 characters. */
5ea5559b 143 while (*f != '\0' && strchr ("0-+ #", *f))
d3ce09f5
SS
144 {
145 if (*f == '#')
146 seen_hash = 1;
147 else if (*f == '0')
148 seen_zero = 1;
149 else if (*f == ' ')
150 seen_space = 1;
151 else if (*f == '+')
152 seen_plus = 1;
153 f++;
154 }
155
156 /* The next part of a format specifier is a width. */
5ea5559b 157 while (*f != '\0' && strchr ("0123456789", *f))
d3ce09f5
SS
158 f++;
159
160 /* The next part of a format specifier is a precision. */
161 if (*f == '.')
162 {
163 seen_prec = 1;
164 f++;
5ea5559b 165 while (*f != '\0' && strchr ("0123456789", *f))
d3ce09f5
SS
166 f++;
167 }
168
169 /* The next part of a format specifier is a length modifier. */
170 if (*f == 'h')
171 {
172 seen_h = 1;
173 f++;
174 }
175 else if (*f == 'l')
176 {
177 f++;
178 lcount++;
179 if (*f == 'l')
180 {
181 f++;
182 lcount++;
183 }
184 }
185 else if (*f == 'L')
186 {
187 seen_big_l = 1;
188 f++;
189 }
190 /* Decimal32 modifier. */
191 else if (*f == 'H')
192 {
193 seen_big_h = 1;
194 f++;
195 }
196 /* Decimal64 and Decimal128 modifiers. */
197 else if (*f == 'D')
198 {
199 f++;
200
201 /* Check for a Decimal128. */
202 if (*f == 'D')
203 {
204 f++;
205 seen_double_big_d = 1;
206 }
207 else
208 seen_big_d = 1;
209 }
210
211 switch (*f)
212 {
213 case 'u':
214 if (seen_hash)
215 bad = 1;
216 /* FALLTHROUGH */
217
218 case 'o':
219 case 'x':
220 case 'X':
221 if (seen_space || seen_plus)
222 bad = 1;
223 /* FALLTHROUGH */
224
225 case 'd':
226 case 'i':
227 if (lcount == 0)
228 this_argclass = int_arg;
229 else if (lcount == 1)
230 this_argclass = long_arg;
231 else
232 this_argclass = long_long_arg;
4ff3ce77
DE
233
234 if (seen_big_l)
235 bad = 1;
236 break;
d3ce09f5
SS
237
238 case 'c':
239 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
240 if (lcount > 1 || seen_h || seen_big_l)
241 bad = 1;
242 if (seen_prec || seen_zero || seen_space || seen_plus)
243 bad = 1;
244 break;
245
246 case 'p':
247 this_argclass = ptr_arg;
248 if (lcount || seen_h || seen_big_l)
249 bad = 1;
5c30d39a
AB
250 if (seen_prec)
251 bad = 1;
252 if (seen_hash || seen_zero || seen_space || seen_plus)
d3ce09f5
SS
253 bad = 1;
254 break;
255
256 case 's':
257 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
258 if (lcount > 1 || seen_h || seen_big_l)
259 bad = 1;
260 if (seen_zero || seen_space || seen_plus)
261 bad = 1;
262 break;
263
264 case 'e':
265 case 'f':
266 case 'g':
267 case 'E':
268 case 'G':
16e812b2
UW
269 if (seen_double_big_d)
270 this_argclass = dec128float_arg;
271 else if (seen_big_d)
272 this_argclass = dec64float_arg;
273 else if (seen_big_h)
274 this_argclass = dec32float_arg;
d3ce09f5
SS
275 else if (seen_big_l)
276 this_argclass = long_double_arg;
277 else
278 this_argclass = double_arg;
279
4ff3ce77
DE
280 if (lcount || seen_h)
281 bad = 1;
282 break;
d3ce09f5
SS
283
284 case '*':
285 error (_("`*' not supported for precision or width in printf"));
286
287 case 'n':
288 error (_("Format specifier `n' not supported in printf"));
289
290 case '\0':
291 error (_("Incomplete format specifier at end of format string"));
292
293 default:
294 error (_("Unrecognized format specifier '%c' in printf"), *f);
295 }
296
297 if (bad)
298 error (_("Inappropriate modifiers to "
299 "format specifier '%c' in printf"),
300 *f);
301
302 f++;
303
304 sub_start = current_substring;
305
306 if (lcount > 1 && USE_PRINTF_I64)
307 {
308 /* Windows' printf does support long long, but not the usual way.
309 Convert %lld to %I64d. */
310 int length_before_ll = f - percent_loc - 1 - lcount;
311
312 strncpy (current_substring, percent_loc, length_before_ll);
313 strcpy (current_substring + length_before_ll, "I64");
314 current_substring[length_before_ll + 3] =
315 percent_loc[length_before_ll + lcount];
316 current_substring += length_before_ll + 4;
317 }
318 else if (this_argclass == wide_string_arg
319 || this_argclass == wide_char_arg)
320 {
321 /* Convert %ls or %lc to %s. */
322 int length_before_ls = f - percent_loc - 2;
323
324 strncpy (current_substring, percent_loc, length_before_ls);
325 strcpy (current_substring + length_before_ls, "s");
326 current_substring += length_before_ls + 2;
327 }
328 else
329 {
330 strncpy (current_substring, percent_loc, f - percent_loc);
331 current_substring += f - percent_loc;
332 }
333
334 *current_substring++ = '\0';
335
336 prev_start = f;
337
8e481c3b 338 m_pieces.emplace_back (sub_start, this_argclass);
d3ce09f5
SS
339 }
340
341 /* Record the remainder of the string. */
342
343 sub_start = current_substring;
344
345 strncpy (current_substring, prev_start, f - prev_start);
346 current_substring += f - prev_start;
347 *current_substring++ = '\0';
348
8e481c3b 349 m_pieces.emplace_back (sub_start, literal_piece);
d3ce09f5 350}
This page took 0.82139 seconds and 4 git commands to generate.