Upgrade GDB from 7.4.1 to 7.6.1 on the vendor branch
[dragonfly.git] / contrib / gdb-7 / gdb / common / format.c
1 /* Parse a printf-style format string.
2
3    Copyright (C) 1986-2013 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 #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
30 struct format_piece *
31 parse_format_string (const char **arg)
32 {
33   const char *s;
34   char *f, *string;
35   const char *prev_start;
36   const char *percent_loc;
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;
249
250             if (seen_big_l)
251               bad = 1;
252             break;
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
290             if (lcount || seen_h)
291               bad = 1;
292             break;
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
373 void
374 free_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
387 void
388 free_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