gdb: Don't skip prologue for explicit line breakpoints in assembler
[deliverable/binutils-gdb.git] / gdb / common / format.c
1 /* Parse a printf-style format string.
2
3 Copyright (C) 1986-2019 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 format_pieces::format_pieces (const char **arg)
24 {
25 const char *s;
26 char *f, *string;
27 const char *prev_start;
28 const char *percent_loc;
29 char *sub_start, *current_substring;
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;
59 case 'e':
60 *f++ = '\e';
61 break;
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
101 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
102 m_storage.reset (current_substring);
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
132 m_pieces.emplace_back (sub_start, literal_piece);
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. */
143 while (*f != '\0' && strchr ("0-+ #", *f))
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. */
157 while (*f != '\0' && strchr ("0123456789", *f))
158 f++;
159
160 /* The next part of a format specifier is a precision. */
161 if (*f == '.')
162 {
163 seen_prec = 1;
164 f++;
165 while (*f != '\0' && strchr ("0123456789", *f))
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;
233
234 if (seen_big_l)
235 bad = 1;
236 break;
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;
250 if (seen_prec)
251 bad = 1;
252 if (seen_hash || seen_zero || seen_space || seen_plus)
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':
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;
275 else if (seen_big_l)
276 this_argclass = long_double_arg;
277 else
278 this_argclass = double_arg;
279
280 if (lcount || seen_h)
281 bad = 1;
282 break;
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
338 m_pieces.emplace_back (sub_start, this_argclass);
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
349 m_pieces.emplace_back (sub_start, literal_piece);
350 }
This page took 0.04344 seconds and 4 git commands to generate.