xref: /dragonfly/contrib/gdb-7/gdb/common/format.c (revision 73610d44)
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 
402