gdb - Local mods (compile)
[dragonfly.git] / contrib / gdb-7 / gdb / common / format.c
CommitLineData
ef5ccd6c
JM
1/* Parse a printf-style format string.
2
25e4902b 3 Copyright (C) 1986-2015 Free Software Foundation, Inc.
ef5ccd6c
JM
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
25e4902b 20#include "common-defs.h"
ef5ccd6c
JM
21#include "format.h"
22
23struct format_piece *
24parse_format_string (const char **arg)
25{
26 const char *s;
27 char *f, *string;
28 const char *prev_start;
29 const char *percent_loc;
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
102 current_substring = xmalloc (strlen (string) * 2 + 1000);
103
104 max_pieces = strlen (string) + 2;
105
106 pieces = (struct format_piece *)
107 xmalloc (max_pieces * sizeof (struct format_piece));
108
109 next_frag = 0;
110
111 /* Now scan the string for %-specs and see what kinds of args they want.
112 argclass classifies the %-specs so we can give printf-type functions
113 something of the right size. */
114
115 f = string;
116 prev_start = string;
117 while (*f)
118 if (*f++ == '%')
119 {
120 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
121 int seen_space = 0, seen_plus = 0;
122 int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
123 int seen_big_d = 0, seen_double_big_d = 0;
124 int bad = 0;
125
126 /* Skip over "%%", it will become part of a literal piece. */
127 if (*f == '%')
128 {
129 f++;
130 continue;
131 }
132
133 sub_start = current_substring;
134
135 strncpy (current_substring, prev_start, f - 1 - prev_start);
136 current_substring += f - 1 - prev_start;
137 *current_substring++ = '\0';
138
139 pieces[next_frag].string = sub_start;
140 pieces[next_frag].argclass = literal_piece;
141 next_frag++;
142
143 percent_loc = f - 1;
144
145 /* Check the validity of the format specifier, and work
146 out what argument it expects. We only accept C89
147 format strings, with the exception of long long (which
148 we autoconf for). */
149
150 /* The first part of a format specifier is a set of flag
151 characters. */
25e4902b 152 while (*f != '\0' && strchr ("0-+ #", *f))
ef5ccd6c
JM
153 {
154 if (*f == '#')
155 seen_hash = 1;
156 else if (*f == '0')
157 seen_zero = 1;
158 else if (*f == ' ')
159 seen_space = 1;
160 else if (*f == '+')
161 seen_plus = 1;
162 f++;
163 }
164
165 /* The next part of a format specifier is a width. */
25e4902b 166 while (*f != '\0' && strchr ("0123456789", *f))
ef5ccd6c
JM
167 f++;
168
169 /* The next part of a format specifier is a precision. */
170 if (*f == '.')
171 {
172 seen_prec = 1;
173 f++;
25e4902b 174 while (*f != '\0' && strchr ("0123456789", *f))
ef5ccd6c
JM
175 f++;
176 }
177
178 /* The next part of a format specifier is a length modifier. */
179 if (*f == 'h')
180 {
181 seen_h = 1;
182 f++;
183 }
184 else if (*f == 'l')
185 {
186 f++;
187 lcount++;
188 if (*f == 'l')
189 {
190 f++;
191 lcount++;
192 }
193 }
194 else if (*f == 'L')
195 {
196 seen_big_l = 1;
197 f++;
198 }
199 /* Decimal32 modifier. */
200 else if (*f == 'H')
201 {
202 seen_big_h = 1;
203 f++;
204 }
205 /* Decimal64 and Decimal128 modifiers. */
206 else if (*f == 'D')
207 {
208 f++;
209
210 /* Check for a Decimal128. */
211 if (*f == 'D')
212 {
213 f++;
214 seen_double_big_d = 1;
215 }
216 else
217 seen_big_d = 1;
218 }
219
220 switch (*f)
221 {
222 case 'u':
223 if (seen_hash)
224 bad = 1;
225 /* FALLTHROUGH */
226
227 case 'o':
228 case 'x':
229 case 'X':
230 if (seen_space || seen_plus)
231 bad = 1;
232 /* FALLTHROUGH */
233
234 case 'd':
235 case 'i':
236 if (lcount == 0)
237 this_argclass = int_arg;
238 else if (lcount == 1)
239 this_argclass = long_arg;
240 else
241 this_argclass = long_long_arg;
242
243 if (seen_big_l)
244 bad = 1;
245 break;
246
247 case 'c':
248 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
249 if (lcount > 1 || seen_h || seen_big_l)
250 bad = 1;
251 if (seen_prec || seen_zero || seen_space || seen_plus)
252 bad = 1;
253 break;
254
255 case 'p':
256 this_argclass = ptr_arg;
257 if (lcount || seen_h || seen_big_l)
258 bad = 1;
25e4902b
AHJ
259 if (seen_prec)
260 bad = 1;
261 if (seen_hash || seen_zero || seen_space || seen_plus)
ef5ccd6c
JM
262 bad = 1;
263 break;
264
265 case 's':
266 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
267 if (lcount > 1 || seen_h || seen_big_l)
268 bad = 1;
269 if (seen_zero || seen_space || seen_plus)
270 bad = 1;
271 break;
272
273 case 'e':
274 case 'f':
275 case 'g':
276 case 'E':
277 case 'G':
278 if (seen_big_h || seen_big_d || seen_double_big_d)
279 this_argclass = decfloat_arg;
280 else if (seen_big_l)
281 this_argclass = long_double_arg;
282 else
283 this_argclass = double_arg;
284
285 if (lcount || seen_h)
286 bad = 1;
287 break;
288
289 case '*':
290 error (_("`*' not supported for precision or width in printf"));
291
292 case 'n':
293 error (_("Format specifier `n' not supported in printf"));
294
295 case '\0':
296 error (_("Incomplete format specifier at end of format string"));
297
298 default:
299 error (_("Unrecognized format specifier '%c' in printf"), *f);
300 }
301
302 if (bad)
303 error (_("Inappropriate modifiers to "
304 "format specifier '%c' in printf"),
305 *f);
306
307 f++;
308
309 sub_start = current_substring;
310
311 if (lcount > 1 && USE_PRINTF_I64)
312 {
313 /* Windows' printf does support long long, but not the usual way.
314 Convert %lld to %I64d. */
315 int length_before_ll = f - percent_loc - 1 - lcount;
316
317 strncpy (current_substring, percent_loc, length_before_ll);
318 strcpy (current_substring + length_before_ll, "I64");
319 current_substring[length_before_ll + 3] =
320 percent_loc[length_before_ll + lcount];
321 current_substring += length_before_ll + 4;
322 }
323 else if (this_argclass == wide_string_arg
324 || this_argclass == wide_char_arg)
325 {
326 /* Convert %ls or %lc to %s. */
327 int length_before_ls = f - percent_loc - 2;
328
329 strncpy (current_substring, percent_loc, length_before_ls);
330 strcpy (current_substring + length_before_ls, "s");
331 current_substring += length_before_ls + 2;
332 }
333 else
334 {
335 strncpy (current_substring, percent_loc, f - percent_loc);
336 current_substring += f - percent_loc;
337 }
338
339 *current_substring++ = '\0';
340
341 prev_start = f;
342
343 pieces[next_frag].string = sub_start;
344 pieces[next_frag].argclass = this_argclass;
345 next_frag++;
346 }
347
348 /* Record the remainder of the string. */
349
350 sub_start = current_substring;
351
352 strncpy (current_substring, prev_start, f - prev_start);
353 current_substring += f - prev_start;
354 *current_substring++ = '\0';
355
356 pieces[next_frag].string = sub_start;
357 pieces[next_frag].argclass = literal_piece;
358 next_frag++;
359
360 /* Record an end-of-array marker. */
361
362 pieces[next_frag].string = NULL;
363 pieces[next_frag].argclass = literal_piece;
364
365 return pieces;
366}
367
368void
369free_format_pieces (struct format_piece *pieces)
370{
371 if (!pieces)
372 return;
373
374 /* We happen to know that all the string pieces are in the block
375 pointed to by the first string piece. */
376 if (pieces[0].string)
377 xfree (pieces[0].string);
378
379 xfree (pieces);
380}
381
382void
383free_format_pieces_cleanup (void *ptr)
384{
385 void **location = ptr;
386
387 if (location == NULL)
388 return;
389
390 if (*location != NULL)
391 {
392 free_format_pieces (*location);
393 *location = NULL;
394 }
395}
396