1e803501ae67ea965812149175e357b2bb1c22f2
[deliverable/binutils-gdb.git] / gdb / gdbsupport / 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, bool gdb_extensions)
24 {
25 const char *s;
26 const char *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 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. */
43
44 char *f = (char *) alloca (strlen (s) + 1);
45 string = f;
46
47 while ((gdb_extensions || *s != '"') && *s != '\0')
48 {
49 int c = *s++;
50 switch (c)
51 {
52 case '\0':
53 continue;
54
55 case '\\':
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 }
93 break;
94
95 default:
96 *f++ = c;
97 }
98 }
99
100 /* Terminate our escape-processed copy. */
101 *f++ = '\0';
102
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 }
107
108 /* Need extra space for the '\0's. Doubling the size is sufficient. */
109
110 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
111 m_storage.reset (current_substring);
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
117 const char *f = string;
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;
126 int bad = 0;
127 int n_int_args = 0;
128
129 /* Skip over "%%", it will become part of a literal piece. */
130 if (*f == '%')
131 {
132 f++;
133 continue;
134 }
135
136 sub_start = current_substring;
137
138 strncpy (current_substring, prev_start, f - 1 - prev_start);
139 current_substring += f - 1 - prev_start;
140 *current_substring++ = '\0';
141
142 if (*sub_start != '\0')
143 m_pieces.emplace_back (sub_start, literal_piece, 0);
144
145 percent_loc = f - 1;
146
147 /* Check the validity of the format specifier, and work
148 out what argument it expects. We only accept C89
149 format strings, with the exception of long long (which
150 we autoconf for). */
151
152 /* The first part of a format specifier is a set of flag
153 characters. */
154 while (*f != '\0' && strchr ("0-+ #", *f))
155 {
156 if (*f == '#')
157 seen_hash = 1;
158 else if (*f == '0')
159 seen_zero = 1;
160 else if (*f == ' ')
161 seen_space = 1;
162 else if (*f == '+')
163 seen_plus = 1;
164 f++;
165 }
166
167 /* The next part of a format specifier is a width. */
168 if (gdb_extensions && *f == '*')
169 {
170 ++f;
171 ++n_int_args;
172 }
173 else
174 {
175 while (*f != '\0' && strchr ("0123456789", *f))
176 f++;
177 }
178
179 /* The next part of a format specifier is a precision. */
180 if (*f == '.')
181 {
182 seen_prec = 1;
183 f++;
184 if (gdb_extensions && *f == '*')
185 {
186 ++f;
187 ++n_int_args;
188 }
189 else
190 {
191 while (*f != '\0' && strchr ("0123456789", *f))
192 f++;
193 }
194 }
195
196 /* The next part of a format specifier is a length modifier. */
197 if (*f == 'h')
198 {
199 seen_h = 1;
200 f++;
201 }
202 else if (*f == 'l')
203 {
204 f++;
205 lcount++;
206 if (*f == 'l')
207 {
208 f++;
209 lcount++;
210 }
211 }
212 else if (*f == 'L')
213 {
214 seen_big_l = 1;
215 f++;
216 }
217 /* Decimal32 modifier. */
218 else if (*f == 'H')
219 {
220 seen_big_h = 1;
221 f++;
222 }
223 /* Decimal64 and Decimal128 modifiers. */
224 else if (*f == 'D')
225 {
226 f++;
227
228 /* Check for a Decimal128. */
229 if (*f == 'D')
230 {
231 f++;
232 seen_double_big_d = 1;
233 }
234 else
235 seen_big_d = 1;
236 }
237
238 switch (*f)
239 {
240 case 'u':
241 if (seen_hash)
242 bad = 1;
243 /* FALLTHROUGH */
244
245 case 'o':
246 case 'x':
247 case 'X':
248 if (seen_space || seen_plus)
249 bad = 1;
250 /* FALLTHROUGH */
251
252 case 'd':
253 case 'i':
254 if (lcount == 0)
255 this_argclass = int_arg;
256 else if (lcount == 1)
257 this_argclass = long_arg;
258 else
259 this_argclass = long_long_arg;
260
261 if (seen_big_l)
262 bad = 1;
263 break;
264
265 case 'c':
266 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
267 if (lcount > 1 || seen_h || seen_big_l)
268 bad = 1;
269 if (seen_prec || seen_zero || seen_space || seen_plus)
270 bad = 1;
271 break;
272
273 case 'p':
274 this_argclass = ptr_arg;
275 if (lcount || seen_h || seen_big_l)
276 bad = 1;
277 if (seen_prec)
278 bad = 1;
279 if (seen_hash || seen_zero || seen_space || seen_plus)
280 bad = 1;
281
282 if (gdb_extensions)
283 {
284 switch (f[1])
285 {
286 case 's':
287 case 'F':
288 case '[':
289 case ']':
290 f++;
291 break;
292 }
293 }
294
295 break;
296
297 case 's':
298 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
299 if (lcount > 1 || seen_h || seen_big_l)
300 bad = 1;
301 if (seen_zero || seen_space || seen_plus)
302 bad = 1;
303 break;
304
305 case 'e':
306 case 'f':
307 case 'g':
308 case 'E':
309 case 'G':
310 if (seen_double_big_d)
311 this_argclass = dec128float_arg;
312 else if (seen_big_d)
313 this_argclass = dec64float_arg;
314 else if (seen_big_h)
315 this_argclass = dec32float_arg;
316 else if (seen_big_l)
317 this_argclass = long_double_arg;
318 else
319 this_argclass = double_arg;
320
321 if (lcount || seen_h)
322 bad = 1;
323 break;
324
325 case '*':
326 error (_("`*' not supported for precision or width in printf"));
327
328 case 'n':
329 error (_("Format specifier `n' not supported in printf"));
330
331 case '\0':
332 error (_("Incomplete format specifier at end of format string"));
333
334 default:
335 error (_("Unrecognized format specifier '%c' in printf"), *f);
336 }
337
338 if (bad)
339 error (_("Inappropriate modifiers to "
340 "format specifier '%c' in printf"),
341 *f);
342
343 f++;
344
345 sub_start = current_substring;
346
347 if (lcount > 1 && USE_PRINTF_I64)
348 {
349 /* Windows' printf does support long long, but not the usual way.
350 Convert %lld to %I64d. */
351 int length_before_ll = f - percent_loc - 1 - lcount;
352
353 strncpy (current_substring, percent_loc, length_before_ll);
354 strcpy (current_substring + length_before_ll, "I64");
355 current_substring[length_before_ll + 3] =
356 percent_loc[length_before_ll + lcount];
357 current_substring += length_before_ll + 4;
358 }
359 else if (this_argclass == wide_string_arg
360 || this_argclass == wide_char_arg)
361 {
362 /* Convert %ls or %lc to %s. */
363 int length_before_ls = f - percent_loc - 2;
364
365 strncpy (current_substring, percent_loc, length_before_ls);
366 strcpy (current_substring + length_before_ls, "s");
367 current_substring += length_before_ls + 2;
368 }
369 else
370 {
371 strncpy (current_substring, percent_loc, f - percent_loc);
372 current_substring += f - percent_loc;
373 }
374
375 *current_substring++ = '\0';
376
377 prev_start = f;
378
379 m_pieces.emplace_back (sub_start, this_argclass, n_int_args);
380 }
381
382 /* Record the remainder of the string. */
383
384 if (f > prev_start)
385 {
386 sub_start = current_substring;
387
388 strncpy (current_substring, prev_start, f - prev_start);
389 current_substring += f - prev_start;
390 *current_substring++ = '\0';
391
392 m_pieces.emplace_back (sub_start, literal_piece, 0);
393 }
394 }
This page took 0.03905 seconds and 3 git commands to generate.