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