Add some more casts (1/2)
[external/binutils.git] / gdb / common / format.c
1 /* Parse a printf-style format string.
2
3    Copyright (C) 1986-2015 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 struct format_piece *
24 parse_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 = (char *) xmalloc (strlen (string) * 2 + 1000);
103
104   max_pieces = strlen (string) + 2;
105
106   pieces = XNEWVEC (struct format_piece, max_pieces);
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.  */
151         while (*f != '\0' && strchr ("0-+ #", *f))
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.  */
165         while (*f != '\0' && strchr ("0123456789", *f))
166           f++;
167
168         /* The next part of a format specifier is a precision.  */
169         if (*f == '.')
170           {
171             seen_prec = 1;
172             f++;
173             while (*f != '\0' && strchr ("0123456789", *f))
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;
241
242             if (seen_big_l)
243               bad = 1;
244             break;
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;
258             if (seen_prec)
259               bad = 1;
260             if (seen_hash || seen_zero || seen_space || seen_plus)
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':
277             if (seen_big_h || seen_big_d || seen_double_big_d)
278               this_argclass = decfloat_arg;
279             else if (seen_big_l)
280               this_argclass = long_double_arg;
281             else
282               this_argclass = double_arg;
283
284             if (lcount || seen_h)
285               bad = 1;
286             break;
287
288           case '*':
289             error (_("`*' not supported for precision or width in printf"));
290
291           case 'n':
292             error (_("Format specifier `n' not supported in printf"));
293
294           case '\0':
295             error (_("Incomplete format specifier at end of format string"));
296
297           default:
298             error (_("Unrecognized format specifier '%c' in printf"), *f);
299           }
300
301         if (bad)
302           error (_("Inappropriate modifiers to "
303                    "format specifier '%c' in printf"),
304                  *f);
305
306         f++;
307
308         sub_start = current_substring;
309
310         if (lcount > 1 && USE_PRINTF_I64)
311           {
312             /* Windows' printf does support long long, but not the usual way.
313                Convert %lld to %I64d.  */
314             int length_before_ll = f - percent_loc - 1 - lcount;
315
316             strncpy (current_substring, percent_loc, length_before_ll);
317             strcpy (current_substring + length_before_ll, "I64");
318             current_substring[length_before_ll + 3] =
319               percent_loc[length_before_ll + lcount];
320             current_substring += length_before_ll + 4;
321           }
322         else if (this_argclass == wide_string_arg
323                  || this_argclass == wide_char_arg)
324           {
325             /* Convert %ls or %lc to %s.  */
326             int length_before_ls = f - percent_loc - 2;
327
328             strncpy (current_substring, percent_loc, length_before_ls);
329             strcpy (current_substring + length_before_ls, "s");
330             current_substring += length_before_ls + 2;
331           }
332         else
333           {
334             strncpy (current_substring, percent_loc, f - percent_loc);
335             current_substring += f - percent_loc;
336           }
337
338         *current_substring++ = '\0';
339
340         prev_start = f;
341
342         pieces[next_frag].string = sub_start;
343         pieces[next_frag].argclass = this_argclass;
344         next_frag++;
345       }
346
347   /* Record the remainder of the string.  */
348
349   sub_start = current_substring;
350
351   strncpy (current_substring, prev_start, f - prev_start);
352   current_substring += f - prev_start;
353   *current_substring++ = '\0';
354
355   pieces[next_frag].string = sub_start;
356   pieces[next_frag].argclass = literal_piece;
357   next_frag++;
358
359   /* Record an end-of-array marker.  */
360
361   pieces[next_frag].string = NULL;
362   pieces[next_frag].argclass = literal_piece;
363
364   return pieces;
365 }
366
367 void
368 free_format_pieces (struct format_piece *pieces)
369 {
370   if (!pieces)
371     return;
372
373   /* We happen to know that all the string pieces are in the block
374      pointed to by the first string piece.  */
375   if (pieces[0].string)
376     xfree (pieces[0].string);
377
378   xfree (pieces);
379 }
380
381 void
382 free_format_pieces_cleanup (void *ptr)
383 {
384   struct format_piece **location = (struct format_piece **) ptr;
385
386   if (location == NULL)
387     return;
388
389   if (*location != NULL)
390     {
391       free_format_pieces (*location);
392       *location = NULL;
393     }
394 }
395