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