xref: /dflybsd-src/contrib/gdb-7/gdb/common/format.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1*ef5ccd6cSJohn Marino /* Parse a printf-style format string.
2*ef5ccd6cSJohn Marino 
3*ef5ccd6cSJohn Marino    Copyright (C) 1986-2013 Free Software Foundation, Inc.
4*ef5ccd6cSJohn Marino 
5*ef5ccd6cSJohn Marino    This file is part of GDB.
6*ef5ccd6cSJohn Marino 
7*ef5ccd6cSJohn Marino    This program is free software; you can redistribute it and/or modify
8*ef5ccd6cSJohn Marino    it under the terms of the GNU General Public License as published by
9*ef5ccd6cSJohn Marino    the Free Software Foundation; either version 3 of the License, or
10*ef5ccd6cSJohn Marino    (at your option) any later version.
11*ef5ccd6cSJohn Marino 
12*ef5ccd6cSJohn Marino    This program is distributed in the hope that it will be useful,
13*ef5ccd6cSJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
14*ef5ccd6cSJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*ef5ccd6cSJohn Marino    GNU General Public License for more details.
16*ef5ccd6cSJohn Marino 
17*ef5ccd6cSJohn Marino    You should have received a copy of the GNU General Public License
18*ef5ccd6cSJohn Marino    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19*ef5ccd6cSJohn Marino 
20*ef5ccd6cSJohn Marino #ifdef GDBSERVER
21*ef5ccd6cSJohn Marino #include "server.h"
22*ef5ccd6cSJohn Marino #else
23*ef5ccd6cSJohn Marino #include "defs.h"
24*ef5ccd6cSJohn Marino #endif
25*ef5ccd6cSJohn Marino 
26*ef5ccd6cSJohn Marino #include <string.h>
27*ef5ccd6cSJohn Marino 
28*ef5ccd6cSJohn Marino #include "format.h"
29*ef5ccd6cSJohn Marino 
30*ef5ccd6cSJohn Marino struct format_piece *
parse_format_string(const char ** arg)31*ef5ccd6cSJohn Marino parse_format_string (const char **arg)
32*ef5ccd6cSJohn Marino {
33*ef5ccd6cSJohn Marino   const char *s;
34*ef5ccd6cSJohn Marino   char *f, *string;
35*ef5ccd6cSJohn Marino   const char *prev_start;
36*ef5ccd6cSJohn Marino   const char *percent_loc;
37*ef5ccd6cSJohn Marino   char *sub_start, *current_substring;
38*ef5ccd6cSJohn Marino   struct format_piece *pieces;
39*ef5ccd6cSJohn Marino   int next_frag;
40*ef5ccd6cSJohn Marino   int max_pieces;
41*ef5ccd6cSJohn Marino   enum argclass this_argclass;
42*ef5ccd6cSJohn Marino 
43*ef5ccd6cSJohn Marino   s = *arg;
44*ef5ccd6cSJohn Marino 
45*ef5ccd6cSJohn Marino   /* Parse the format-control string and copy it into the string STRING,
46*ef5ccd6cSJohn Marino      processing some kinds of escape sequence.  */
47*ef5ccd6cSJohn Marino 
48*ef5ccd6cSJohn Marino   f = string = (char *) alloca (strlen (s) + 1);
49*ef5ccd6cSJohn Marino 
50*ef5ccd6cSJohn Marino   while (*s != '"' && *s != '\0')
51*ef5ccd6cSJohn Marino     {
52*ef5ccd6cSJohn Marino       int c = *s++;
53*ef5ccd6cSJohn Marino       switch (c)
54*ef5ccd6cSJohn Marino 	{
55*ef5ccd6cSJohn Marino 	case '\0':
56*ef5ccd6cSJohn Marino 	  continue;
57*ef5ccd6cSJohn Marino 
58*ef5ccd6cSJohn Marino 	case '\\':
59*ef5ccd6cSJohn Marino 	  switch (c = *s++)
60*ef5ccd6cSJohn Marino 	    {
61*ef5ccd6cSJohn Marino 	    case '\\':
62*ef5ccd6cSJohn Marino 	      *f++ = '\\';
63*ef5ccd6cSJohn Marino 	      break;
64*ef5ccd6cSJohn Marino 	    case 'a':
65*ef5ccd6cSJohn Marino 	      *f++ = '\a';
66*ef5ccd6cSJohn Marino 	      break;
67*ef5ccd6cSJohn Marino 	    case 'b':
68*ef5ccd6cSJohn Marino 	      *f++ = '\b';
69*ef5ccd6cSJohn Marino 	      break;
70*ef5ccd6cSJohn Marino 	    case 'f':
71*ef5ccd6cSJohn Marino 	      *f++ = '\f';
72*ef5ccd6cSJohn Marino 	      break;
73*ef5ccd6cSJohn Marino 	    case 'n':
74*ef5ccd6cSJohn Marino 	      *f++ = '\n';
75*ef5ccd6cSJohn Marino 	      break;
76*ef5ccd6cSJohn Marino 	    case 'r':
77*ef5ccd6cSJohn Marino 	      *f++ = '\r';
78*ef5ccd6cSJohn Marino 	      break;
79*ef5ccd6cSJohn Marino 	    case 't':
80*ef5ccd6cSJohn Marino 	      *f++ = '\t';
81*ef5ccd6cSJohn Marino 	      break;
82*ef5ccd6cSJohn Marino 	    case 'v':
83*ef5ccd6cSJohn Marino 	      *f++ = '\v';
84*ef5ccd6cSJohn Marino 	      break;
85*ef5ccd6cSJohn Marino 	    case '"':
86*ef5ccd6cSJohn Marino 	      *f++ = '"';
87*ef5ccd6cSJohn Marino 	      break;
88*ef5ccd6cSJohn Marino 	    default:
89*ef5ccd6cSJohn Marino 	      /* ??? TODO: handle other escape sequences.  */
90*ef5ccd6cSJohn Marino 	      error (_("Unrecognized escape character \\%c in format string."),
91*ef5ccd6cSJohn Marino 		     c);
92*ef5ccd6cSJohn Marino 	    }
93*ef5ccd6cSJohn Marino 	  break;
94*ef5ccd6cSJohn Marino 
95*ef5ccd6cSJohn Marino 	default:
96*ef5ccd6cSJohn Marino 	  *f++ = c;
97*ef5ccd6cSJohn Marino 	}
98*ef5ccd6cSJohn Marino     }
99*ef5ccd6cSJohn Marino 
100*ef5ccd6cSJohn Marino   /* Terminate our escape-processed copy.  */
101*ef5ccd6cSJohn Marino   *f++ = '\0';
102*ef5ccd6cSJohn Marino 
103*ef5ccd6cSJohn Marino   /* Whether the format string ended with double-quote or zero, we're
104*ef5ccd6cSJohn Marino      done with it; it's up to callers to complain about syntax.  */
105*ef5ccd6cSJohn Marino   *arg = s;
106*ef5ccd6cSJohn Marino 
107*ef5ccd6cSJohn Marino   /* Need extra space for the '\0's.  Doubling the size is sufficient.  */
108*ef5ccd6cSJohn Marino 
109*ef5ccd6cSJohn Marino   current_substring = xmalloc (strlen (string) * 2 + 1000);
110*ef5ccd6cSJohn Marino 
111*ef5ccd6cSJohn Marino   max_pieces = strlen (string) + 2;
112*ef5ccd6cSJohn Marino 
113*ef5ccd6cSJohn Marino   pieces = (struct format_piece *)
114*ef5ccd6cSJohn Marino     xmalloc (max_pieces * sizeof (struct format_piece));
115*ef5ccd6cSJohn Marino 
116*ef5ccd6cSJohn Marino   next_frag = 0;
117*ef5ccd6cSJohn Marino 
118*ef5ccd6cSJohn Marino   /* Now scan the string for %-specs and see what kinds of args they want.
119*ef5ccd6cSJohn Marino      argclass classifies the %-specs so we can give printf-type functions
120*ef5ccd6cSJohn Marino      something of the right size.  */
121*ef5ccd6cSJohn Marino 
122*ef5ccd6cSJohn Marino   f = string;
123*ef5ccd6cSJohn Marino   prev_start = string;
124*ef5ccd6cSJohn Marino   while (*f)
125*ef5ccd6cSJohn Marino     if (*f++ == '%')
126*ef5ccd6cSJohn Marino       {
127*ef5ccd6cSJohn Marino 	int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
128*ef5ccd6cSJohn Marino 	int seen_space = 0, seen_plus = 0;
129*ef5ccd6cSJohn Marino 	int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
130*ef5ccd6cSJohn Marino 	int seen_big_d = 0, seen_double_big_d = 0;
131*ef5ccd6cSJohn Marino 	int bad = 0;
132*ef5ccd6cSJohn Marino 
133*ef5ccd6cSJohn Marino 	/* Skip over "%%", it will become part of a literal piece.  */
134*ef5ccd6cSJohn Marino 	if (*f == '%')
135*ef5ccd6cSJohn Marino 	  {
136*ef5ccd6cSJohn Marino 	    f++;
137*ef5ccd6cSJohn Marino 	    continue;
138*ef5ccd6cSJohn Marino 	  }
139*ef5ccd6cSJohn Marino 
140*ef5ccd6cSJohn Marino 	sub_start = current_substring;
141*ef5ccd6cSJohn Marino 
142*ef5ccd6cSJohn Marino 	strncpy (current_substring, prev_start, f - 1 - prev_start);
143*ef5ccd6cSJohn Marino 	current_substring += f - 1 - prev_start;
144*ef5ccd6cSJohn Marino 	*current_substring++ = '\0';
145*ef5ccd6cSJohn Marino 
146*ef5ccd6cSJohn Marino 	pieces[next_frag].string = sub_start;
147*ef5ccd6cSJohn Marino 	pieces[next_frag].argclass = literal_piece;
148*ef5ccd6cSJohn Marino 	next_frag++;
149*ef5ccd6cSJohn Marino 
150*ef5ccd6cSJohn Marino 	percent_loc = f - 1;
151*ef5ccd6cSJohn Marino 
152*ef5ccd6cSJohn Marino 	/* Check the validity of the format specifier, and work
153*ef5ccd6cSJohn Marino 	   out what argument it expects.  We only accept C89
154*ef5ccd6cSJohn Marino 	   format strings, with the exception of long long (which
155*ef5ccd6cSJohn Marino 	   we autoconf for).  */
156*ef5ccd6cSJohn Marino 
157*ef5ccd6cSJohn Marino 	/* The first part of a format specifier is a set of flag
158*ef5ccd6cSJohn Marino 	   characters.  */
159*ef5ccd6cSJohn Marino 	while (strchr ("0-+ #", *f))
160*ef5ccd6cSJohn Marino 	  {
161*ef5ccd6cSJohn Marino 	    if (*f == '#')
162*ef5ccd6cSJohn Marino 	      seen_hash = 1;
163*ef5ccd6cSJohn Marino 	    else if (*f == '0')
164*ef5ccd6cSJohn Marino 	      seen_zero = 1;
165*ef5ccd6cSJohn Marino 	    else if (*f == ' ')
166*ef5ccd6cSJohn Marino 	      seen_space = 1;
167*ef5ccd6cSJohn Marino 	    else if (*f == '+')
168*ef5ccd6cSJohn Marino 	      seen_plus = 1;
169*ef5ccd6cSJohn Marino 	    f++;
170*ef5ccd6cSJohn Marino 	  }
171*ef5ccd6cSJohn Marino 
172*ef5ccd6cSJohn Marino 	/* The next part of a format specifier is a width.  */
173*ef5ccd6cSJohn Marino 	while (strchr ("0123456789", *f))
174*ef5ccd6cSJohn Marino 	  f++;
175*ef5ccd6cSJohn Marino 
176*ef5ccd6cSJohn Marino 	/* The next part of a format specifier is a precision.  */
177*ef5ccd6cSJohn Marino 	if (*f == '.')
178*ef5ccd6cSJohn Marino 	  {
179*ef5ccd6cSJohn Marino 	    seen_prec = 1;
180*ef5ccd6cSJohn Marino 	    f++;
181*ef5ccd6cSJohn Marino 	    while (strchr ("0123456789", *f))
182*ef5ccd6cSJohn Marino 	      f++;
183*ef5ccd6cSJohn Marino 	  }
184*ef5ccd6cSJohn Marino 
185*ef5ccd6cSJohn Marino 	/* The next part of a format specifier is a length modifier.  */
186*ef5ccd6cSJohn Marino 	if (*f == 'h')
187*ef5ccd6cSJohn Marino 	  {
188*ef5ccd6cSJohn Marino 	    seen_h = 1;
189*ef5ccd6cSJohn Marino 	    f++;
190*ef5ccd6cSJohn Marino 	  }
191*ef5ccd6cSJohn Marino 	else if (*f == 'l')
192*ef5ccd6cSJohn Marino 	  {
193*ef5ccd6cSJohn Marino 	    f++;
194*ef5ccd6cSJohn Marino 	    lcount++;
195*ef5ccd6cSJohn Marino 	    if (*f == 'l')
196*ef5ccd6cSJohn Marino 	      {
197*ef5ccd6cSJohn Marino 		f++;
198*ef5ccd6cSJohn Marino 		lcount++;
199*ef5ccd6cSJohn Marino 	      }
200*ef5ccd6cSJohn Marino 	  }
201*ef5ccd6cSJohn Marino 	else if (*f == 'L')
202*ef5ccd6cSJohn Marino 	  {
203*ef5ccd6cSJohn Marino 	    seen_big_l = 1;
204*ef5ccd6cSJohn Marino 	    f++;
205*ef5ccd6cSJohn Marino 	  }
206*ef5ccd6cSJohn Marino 	/* Decimal32 modifier.  */
207*ef5ccd6cSJohn Marino 	else if (*f == 'H')
208*ef5ccd6cSJohn Marino 	  {
209*ef5ccd6cSJohn Marino 	    seen_big_h = 1;
210*ef5ccd6cSJohn Marino 	    f++;
211*ef5ccd6cSJohn Marino 	  }
212*ef5ccd6cSJohn Marino 	/* Decimal64 and Decimal128 modifiers.  */
213*ef5ccd6cSJohn Marino 	else if (*f == 'D')
214*ef5ccd6cSJohn Marino 	  {
215*ef5ccd6cSJohn Marino 	    f++;
216*ef5ccd6cSJohn Marino 
217*ef5ccd6cSJohn Marino 	    /* Check for a Decimal128.  */
218*ef5ccd6cSJohn Marino 	    if (*f == 'D')
219*ef5ccd6cSJohn Marino 	      {
220*ef5ccd6cSJohn Marino 		f++;
221*ef5ccd6cSJohn Marino 		seen_double_big_d = 1;
222*ef5ccd6cSJohn Marino 	      }
223*ef5ccd6cSJohn Marino 	    else
224*ef5ccd6cSJohn Marino 	      seen_big_d = 1;
225*ef5ccd6cSJohn Marino 	  }
226*ef5ccd6cSJohn Marino 
227*ef5ccd6cSJohn Marino 	switch (*f)
228*ef5ccd6cSJohn Marino 	  {
229*ef5ccd6cSJohn Marino 	  case 'u':
230*ef5ccd6cSJohn Marino 	    if (seen_hash)
231*ef5ccd6cSJohn Marino 	      bad = 1;
232*ef5ccd6cSJohn Marino 	    /* FALLTHROUGH */
233*ef5ccd6cSJohn Marino 
234*ef5ccd6cSJohn Marino 	  case 'o':
235*ef5ccd6cSJohn Marino 	  case 'x':
236*ef5ccd6cSJohn Marino 	  case 'X':
237*ef5ccd6cSJohn Marino 	    if (seen_space || seen_plus)
238*ef5ccd6cSJohn Marino 	      bad = 1;
239*ef5ccd6cSJohn Marino 	  /* FALLTHROUGH */
240*ef5ccd6cSJohn Marino 
241*ef5ccd6cSJohn Marino 	  case 'd':
242*ef5ccd6cSJohn Marino 	  case 'i':
243*ef5ccd6cSJohn Marino 	    if (lcount == 0)
244*ef5ccd6cSJohn Marino 	      this_argclass = int_arg;
245*ef5ccd6cSJohn Marino 	    else if (lcount == 1)
246*ef5ccd6cSJohn Marino 	      this_argclass = long_arg;
247*ef5ccd6cSJohn Marino 	    else
248*ef5ccd6cSJohn Marino 	      this_argclass = long_long_arg;
249*ef5ccd6cSJohn Marino 
250*ef5ccd6cSJohn Marino 	    if (seen_big_l)
251*ef5ccd6cSJohn Marino 	      bad = 1;
252*ef5ccd6cSJohn Marino 	    break;
253*ef5ccd6cSJohn Marino 
254*ef5ccd6cSJohn Marino 	  case 'c':
255*ef5ccd6cSJohn Marino 	    this_argclass = lcount == 0 ? int_arg : wide_char_arg;
256*ef5ccd6cSJohn Marino 	    if (lcount > 1 || seen_h || seen_big_l)
257*ef5ccd6cSJohn Marino 	      bad = 1;
258*ef5ccd6cSJohn Marino 	    if (seen_prec || seen_zero || seen_space || seen_plus)
259*ef5ccd6cSJohn Marino 	      bad = 1;
260*ef5ccd6cSJohn Marino 	    break;
261*ef5ccd6cSJohn Marino 
262*ef5ccd6cSJohn Marino 	  case 'p':
263*ef5ccd6cSJohn Marino 	    this_argclass = ptr_arg;
264*ef5ccd6cSJohn Marino 	    if (lcount || seen_h || seen_big_l)
265*ef5ccd6cSJohn Marino 	      bad = 1;
266*ef5ccd6cSJohn Marino 	    if (seen_prec || seen_zero || seen_space || seen_plus)
267*ef5ccd6cSJohn Marino 	      bad = 1;
268*ef5ccd6cSJohn Marino 	    break;
269*ef5ccd6cSJohn Marino 
270*ef5ccd6cSJohn Marino 	  case 's':
271*ef5ccd6cSJohn Marino 	    this_argclass = lcount == 0 ? string_arg : wide_string_arg;
272*ef5ccd6cSJohn Marino 	    if (lcount > 1 || seen_h || seen_big_l)
273*ef5ccd6cSJohn Marino 	      bad = 1;
274*ef5ccd6cSJohn Marino 	    if (seen_zero || seen_space || seen_plus)
275*ef5ccd6cSJohn Marino 	      bad = 1;
276*ef5ccd6cSJohn Marino 	    break;
277*ef5ccd6cSJohn Marino 
278*ef5ccd6cSJohn Marino 	  case 'e':
279*ef5ccd6cSJohn Marino 	  case 'f':
280*ef5ccd6cSJohn Marino 	  case 'g':
281*ef5ccd6cSJohn Marino 	  case 'E':
282*ef5ccd6cSJohn Marino 	  case 'G':
283*ef5ccd6cSJohn Marino 	    if (seen_big_h || seen_big_d || seen_double_big_d)
284*ef5ccd6cSJohn Marino 	      this_argclass = decfloat_arg;
285*ef5ccd6cSJohn Marino 	    else if (seen_big_l)
286*ef5ccd6cSJohn Marino 	      this_argclass = long_double_arg;
287*ef5ccd6cSJohn Marino 	    else
288*ef5ccd6cSJohn Marino 	      this_argclass = double_arg;
289*ef5ccd6cSJohn Marino 
290*ef5ccd6cSJohn Marino 	    if (lcount || seen_h)
291*ef5ccd6cSJohn Marino 	      bad = 1;
292*ef5ccd6cSJohn Marino 	    break;
293*ef5ccd6cSJohn Marino 
294*ef5ccd6cSJohn Marino 	  case '*':
295*ef5ccd6cSJohn Marino 	    error (_("`*' not supported for precision or width in printf"));
296*ef5ccd6cSJohn Marino 
297*ef5ccd6cSJohn Marino 	  case 'n':
298*ef5ccd6cSJohn Marino 	    error (_("Format specifier `n' not supported in printf"));
299*ef5ccd6cSJohn Marino 
300*ef5ccd6cSJohn Marino 	  case '\0':
301*ef5ccd6cSJohn Marino 	    error (_("Incomplete format specifier at end of format string"));
302*ef5ccd6cSJohn Marino 
303*ef5ccd6cSJohn Marino 	  default:
304*ef5ccd6cSJohn Marino 	    error (_("Unrecognized format specifier '%c' in printf"), *f);
305*ef5ccd6cSJohn Marino 	  }
306*ef5ccd6cSJohn Marino 
307*ef5ccd6cSJohn Marino 	if (bad)
308*ef5ccd6cSJohn Marino 	  error (_("Inappropriate modifiers to "
309*ef5ccd6cSJohn Marino 		   "format specifier '%c' in printf"),
310*ef5ccd6cSJohn Marino 		 *f);
311*ef5ccd6cSJohn Marino 
312*ef5ccd6cSJohn Marino 	f++;
313*ef5ccd6cSJohn Marino 
314*ef5ccd6cSJohn Marino 	sub_start = current_substring;
315*ef5ccd6cSJohn Marino 
316*ef5ccd6cSJohn Marino 	if (lcount > 1 && USE_PRINTF_I64)
317*ef5ccd6cSJohn Marino 	  {
318*ef5ccd6cSJohn Marino 	    /* Windows' printf does support long long, but not the usual way.
319*ef5ccd6cSJohn Marino 	       Convert %lld to %I64d.  */
320*ef5ccd6cSJohn Marino 	    int length_before_ll = f - percent_loc - 1 - lcount;
321*ef5ccd6cSJohn Marino 
322*ef5ccd6cSJohn Marino 	    strncpy (current_substring, percent_loc, length_before_ll);
323*ef5ccd6cSJohn Marino 	    strcpy (current_substring + length_before_ll, "I64");
324*ef5ccd6cSJohn Marino 	    current_substring[length_before_ll + 3] =
325*ef5ccd6cSJohn Marino 	      percent_loc[length_before_ll + lcount];
326*ef5ccd6cSJohn Marino 	    current_substring += length_before_ll + 4;
327*ef5ccd6cSJohn Marino 	  }
328*ef5ccd6cSJohn Marino 	else if (this_argclass == wide_string_arg
329*ef5ccd6cSJohn Marino 		 || this_argclass == wide_char_arg)
330*ef5ccd6cSJohn Marino 	  {
331*ef5ccd6cSJohn Marino 	    /* Convert %ls or %lc to %s.  */
332*ef5ccd6cSJohn Marino 	    int length_before_ls = f - percent_loc - 2;
333*ef5ccd6cSJohn Marino 
334*ef5ccd6cSJohn Marino 	    strncpy (current_substring, percent_loc, length_before_ls);
335*ef5ccd6cSJohn Marino 	    strcpy (current_substring + length_before_ls, "s");
336*ef5ccd6cSJohn Marino 	    current_substring += length_before_ls + 2;
337*ef5ccd6cSJohn Marino 	  }
338*ef5ccd6cSJohn Marino 	else
339*ef5ccd6cSJohn Marino 	  {
340*ef5ccd6cSJohn Marino 	    strncpy (current_substring, percent_loc, f - percent_loc);
341*ef5ccd6cSJohn Marino 	    current_substring += f - percent_loc;
342*ef5ccd6cSJohn Marino 	  }
343*ef5ccd6cSJohn Marino 
344*ef5ccd6cSJohn Marino 	*current_substring++ = '\0';
345*ef5ccd6cSJohn Marino 
346*ef5ccd6cSJohn Marino 	prev_start = f;
347*ef5ccd6cSJohn Marino 
348*ef5ccd6cSJohn Marino 	pieces[next_frag].string = sub_start;
349*ef5ccd6cSJohn Marino 	pieces[next_frag].argclass = this_argclass;
350*ef5ccd6cSJohn Marino 	next_frag++;
351*ef5ccd6cSJohn Marino       }
352*ef5ccd6cSJohn Marino 
353*ef5ccd6cSJohn Marino   /* Record the remainder of the string.  */
354*ef5ccd6cSJohn Marino 
355*ef5ccd6cSJohn Marino   sub_start = current_substring;
356*ef5ccd6cSJohn Marino 
357*ef5ccd6cSJohn Marino   strncpy (current_substring, prev_start, f - prev_start);
358*ef5ccd6cSJohn Marino   current_substring += f - prev_start;
359*ef5ccd6cSJohn Marino   *current_substring++ = '\0';
360*ef5ccd6cSJohn Marino 
361*ef5ccd6cSJohn Marino   pieces[next_frag].string = sub_start;
362*ef5ccd6cSJohn Marino   pieces[next_frag].argclass = literal_piece;
363*ef5ccd6cSJohn Marino   next_frag++;
364*ef5ccd6cSJohn Marino 
365*ef5ccd6cSJohn Marino   /* Record an end-of-array marker.  */
366*ef5ccd6cSJohn Marino 
367*ef5ccd6cSJohn Marino   pieces[next_frag].string = NULL;
368*ef5ccd6cSJohn Marino   pieces[next_frag].argclass = literal_piece;
369*ef5ccd6cSJohn Marino 
370*ef5ccd6cSJohn Marino   return pieces;
371*ef5ccd6cSJohn Marino }
372*ef5ccd6cSJohn Marino 
373*ef5ccd6cSJohn Marino void
free_format_pieces(struct format_piece * pieces)374*ef5ccd6cSJohn Marino free_format_pieces (struct format_piece *pieces)
375*ef5ccd6cSJohn Marino {
376*ef5ccd6cSJohn Marino   if (!pieces)
377*ef5ccd6cSJohn Marino     return;
378*ef5ccd6cSJohn Marino 
379*ef5ccd6cSJohn Marino   /* We happen to know that all the string pieces are in the block
380*ef5ccd6cSJohn Marino      pointed to by the first string piece.  */
381*ef5ccd6cSJohn Marino   if (pieces[0].string)
382*ef5ccd6cSJohn Marino     xfree (pieces[0].string);
383*ef5ccd6cSJohn Marino 
384*ef5ccd6cSJohn Marino   xfree (pieces);
385*ef5ccd6cSJohn Marino }
386*ef5ccd6cSJohn Marino 
387*ef5ccd6cSJohn Marino void
free_format_pieces_cleanup(void * ptr)388*ef5ccd6cSJohn Marino free_format_pieces_cleanup (void *ptr)
389*ef5ccd6cSJohn Marino {
390*ef5ccd6cSJohn Marino   void **location = ptr;
391*ef5ccd6cSJohn Marino 
392*ef5ccd6cSJohn Marino   if (location == NULL)
393*ef5ccd6cSJohn Marino     return;
394*ef5ccd6cSJohn Marino 
395*ef5ccd6cSJohn Marino   if (*location != NULL)
396*ef5ccd6cSJohn Marino     {
397*ef5ccd6cSJohn Marino       free_format_pieces (*location);
398*ef5ccd6cSJohn Marino       *location = NULL;
399*ef5ccd6cSJohn Marino     }
400*ef5ccd6cSJohn Marino }
401*ef5ccd6cSJohn Marino 
402