deea93ca9536be8d616164b93d1fe255f19b764b
[dragonfly.git] / contrib / gdb-7 / 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 = 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.  */
152         while (*f != '\0' && strchr ("0-+ #", *f))
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.  */
166         while (*f != '\0' && strchr ("0123456789", *f))
167           f++;
168
169         /* The next part of a format specifier is a precision.  */
170         if (*f == '.')
171           {
172             seen_prec = 1;
173             f++;
174             while (*f != '\0' && strchr ("0123456789", *f))
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;
259             if (seen_prec)
260               bad = 1;
261             if (seen_hash || seen_zero || seen_space || seen_plus)
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
368 void
369 free_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
382 void
383 free_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