xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/format-gcc-internal.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1*946379e7Schristos /* GCC internal format strings.
2*946379e7Schristos    Copyright (C) 2003-2006 Free Software Foundation, Inc.
3*946379e7Schristos    Written by Bruno Haible <bruno@clisp.org>, 2003.
4*946379e7Schristos 
5*946379e7Schristos    This program is free software; you can redistribute it and/or modify
6*946379e7Schristos    it under the terms of the GNU General Public License as published by
7*946379e7Schristos    the Free Software Foundation; either version 2, or (at your option)
8*946379e7Schristos    any later version.
9*946379e7Schristos 
10*946379e7Schristos    This program is distributed in the hope that it will be useful,
11*946379e7Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*946379e7Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*946379e7Schristos    GNU General Public License for more details.
14*946379e7Schristos 
15*946379e7Schristos    You should have received a copy of the GNU General Public License
16*946379e7Schristos    along with this program; if not, write to the Free Software Foundation,
17*946379e7Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18*946379e7Schristos 
19*946379e7Schristos #ifdef HAVE_CONFIG_H
20*946379e7Schristos # include <config.h>
21*946379e7Schristos #endif
22*946379e7Schristos 
23*946379e7Schristos #include <stdbool.h>
24*946379e7Schristos #include <stdlib.h>
25*946379e7Schristos 
26*946379e7Schristos #include "format.h"
27*946379e7Schristos #include "c-ctype.h"
28*946379e7Schristos #include "xalloc.h"
29*946379e7Schristos #include "xvasprintf.h"
30*946379e7Schristos #include "format-invalid.h"
31*946379e7Schristos #include "gettext.h"
32*946379e7Schristos 
33*946379e7Schristos #define _(str) gettext (str)
34*946379e7Schristos 
35*946379e7Schristos /* GCC internal format strings consist of language frontend independent
36*946379e7Schristos    format directives, implemented in gcc-4.1.0/gcc/pretty-print.c (function
37*946379e7Schristos    pp_base_format), plus some frontend dependent extensions:
38*946379e7Schristos      - for the C/ObjC frontend
39*946379e7Schristos        in gcc-4.1.0/gcc/c-objc-common.c (function c_tree_printer)
40*946379e7Schristos      - for the C++ frontend
41*946379e7Schristos        in gcc-4.1.0/gcc/cp/error.c (function cp_printer)
42*946379e7Schristos    Taking these together, GCC internal format strings are specified as follows.
43*946379e7Schristos 
44*946379e7Schristos    A directive
45*946379e7Schristos    - starts with '%',
46*946379e7Schristos    - either is finished by one of these:
47*946379e7Schristos        - '%', '<', '>', "'", that need no argument,
48*946379e7Schristos        - 'm', that needs no argument but looks at an err_no variable,
49*946379e7Schristos    - or is continued like this:
50*946379e7Schristos        - optionally 'm$' where m is a positive integer,
51*946379e7Schristos        - optionally any number of flags:
52*946379e7Schristos          'q' (once only),
53*946379e7Schristos          'l' (up to twice) or 'w' (once only) (exclusive),
54*946379e7Schristos          '+' (once only),
55*946379e7Schristos          '#' (once only),
56*946379e7Schristos        - finished by a specifier
57*946379e7Schristos 
58*946379e7Schristos            - 'c', that needs a character argument,
59*946379e7Schristos            - 's', that needs a string argument,
60*946379e7Schristos            - '.NNNs', where NNN is a nonempty digit sequence, that needs a
61*946379e7Schristos              string argument,
62*946379e7Schristos            - '.*NNN$s' where NNN is a positive integer and NNN = m - 1, that
63*946379e7Schristos              needs a signed integer argument at position NNN and a string
64*946379e7Schristos              argument,
65*946379e7Schristos            - '.*s', that needs a signed integer argument and a string argument,
66*946379e7Schristos            - 'i', 'd', that need a signed integer argument of the specified
67*946379e7Schristos              size,
68*946379e7Schristos            - 'o', 'u', 'x', that need an unsigned integer argument of the
69*946379e7Schristos              specified size,
70*946379e7Schristos            - 'p', that needs a 'void *' argument,
71*946379e7Schristos            - 'H', that needs a 'location_t *' argument,
72*946379e7Schristos            - 'J', that needs a general declaration argument,
73*946379e7Schristos              [see gcc/pretty-print.c]
74*946379e7Schristos 
75*946379e7Schristos            - 'D', that needs a general declaration argument,
76*946379e7Schristos            - 'F', that needs a function declaration argument,
77*946379e7Schristos            - 'T', that needs a type argument,
78*946379e7Schristos            - 'E', that needs an expression argument,
79*946379e7Schristos              [see gcc/c-objc-common.c and gcc/cp/error.c]
80*946379e7Schristos 
81*946379e7Schristos            - 'A', that needs a function argument list argument,
82*946379e7Schristos            - 'C', that needs a tree code argument,
83*946379e7Schristos            - 'L', that needs a language argument,
84*946379e7Schristos            - 'O', that needs a binary operator argument,
85*946379e7Schristos            - 'P', that needs a function parameter argument,
86*946379e7Schristos            - 'Q', that needs an assignment operator argument,
87*946379e7Schristos            - 'V', that needs a const/volatile qualifier argument.
88*946379e7Schristos              [see gcc/cp/error.c]
89*946379e7Schristos 
90*946379e7Schristos    Numbered ('%m$' or '*m$') and unnumbered argument specifications cannot
91*946379e7Schristos    be used in the same string.  */
92*946379e7Schristos 
93*946379e7Schristos enum format_arg_type
94*946379e7Schristos {
95*946379e7Schristos   FAT_NONE		= 0,
96*946379e7Schristos   /* Basic types */
97*946379e7Schristos   FAT_INTEGER		= 1,
98*946379e7Schristos   FAT_CHAR		= 2,
99*946379e7Schristos   FAT_STRING		= 3,
100*946379e7Schristos   FAT_POINTER		= 4,
101*946379e7Schristos   FAT_LOCATION		= 5,
102*946379e7Schristos   FAT_TREE		= 6,
103*946379e7Schristos   FAT_TREE_CODE		= 7,
104*946379e7Schristos   FAT_LANGUAGES		= 8,
105*946379e7Schristos   /* Flags */
106*946379e7Schristos   FAT_UNSIGNED		= 1 << 4,
107*946379e7Schristos   FAT_SIZE_LONG		= 1 << 5,
108*946379e7Schristos   FAT_SIZE_LONGLONG	= 2 << 5,
109*946379e7Schristos   FAT_SIZE_WIDE		= 3 << 5,
110*946379e7Schristos   FAT_TREE_DECL		= 1 << 7,
111*946379e7Schristos   FAT_TREE_FUNCDECL	= 2 << 7,
112*946379e7Schristos   FAT_TREE_TYPE		= 3 << 7,
113*946379e7Schristos   FAT_TREE_ARGUMENT	= 4 << 7,
114*946379e7Schristos   FAT_TREE_EXPRESSION	= 5 << 7,
115*946379e7Schristos   FAT_TREE_CV		= 6 << 7,
116*946379e7Schristos   FAT_TREE_CODE_BINOP	= 1 << 10,
117*946379e7Schristos   FAT_TREE_CODE_ASSOP	= 2 << 10,
118*946379e7Schristos   FAT_FUNCPARAM		= 1 << 12,
119*946379e7Schristos   /* Bitmasks */
120*946379e7Schristos   FAT_SIZE_MASK		= (FAT_SIZE_LONG | FAT_SIZE_LONGLONG | FAT_SIZE_WIDE)
121*946379e7Schristos };
122*946379e7Schristos 
123*946379e7Schristos struct numbered_arg
124*946379e7Schristos {
125*946379e7Schristos   unsigned int number;
126*946379e7Schristos   enum format_arg_type type;
127*946379e7Schristos };
128*946379e7Schristos 
129*946379e7Schristos struct spec
130*946379e7Schristos {
131*946379e7Schristos   unsigned int directives;
132*946379e7Schristos   unsigned int numbered_arg_count;
133*946379e7Schristos   unsigned int allocated;
134*946379e7Schristos   struct numbered_arg *numbered;
135*946379e7Schristos   bool uses_err_no;
136*946379e7Schristos };
137*946379e7Schristos 
138*946379e7Schristos /* Locale independent test for a decimal digit.
139*946379e7Schristos    Argument can be  'char' or 'unsigned char'.  (Whereas the argument of
140*946379e7Schristos    <ctype.h> isdigit must be an 'unsigned char'.)  */
141*946379e7Schristos #undef isdigit
142*946379e7Schristos #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
143*946379e7Schristos 
144*946379e7Schristos 
145*946379e7Schristos static int
numbered_arg_compare(const void * p1,const void * p2)146*946379e7Schristos numbered_arg_compare (const void *p1, const void *p2)
147*946379e7Schristos {
148*946379e7Schristos   unsigned int n1 = ((const struct numbered_arg *) p1)->number;
149*946379e7Schristos   unsigned int n2 = ((const struct numbered_arg *) p2)->number;
150*946379e7Schristos 
151*946379e7Schristos   return (n1 > n2 ? 1 : n1 < n2 ? -1 : 0);
152*946379e7Schristos }
153*946379e7Schristos 
154*946379e7Schristos static void *
format_parse(const char * format,bool translated,char ** invalid_reason)155*946379e7Schristos format_parse (const char *format, bool translated, char **invalid_reason)
156*946379e7Schristos {
157*946379e7Schristos   struct spec spec;
158*946379e7Schristos   unsigned int unnumbered_arg_count;
159*946379e7Schristos   struct spec *result;
160*946379e7Schristos 
161*946379e7Schristos   spec.directives = 0;
162*946379e7Schristos   spec.numbered_arg_count = 0;
163*946379e7Schristos   spec.allocated = 0;
164*946379e7Schristos   spec.numbered = NULL;
165*946379e7Schristos   spec.uses_err_no = false;
166*946379e7Schristos   unnumbered_arg_count = 0;
167*946379e7Schristos 
168*946379e7Schristos   for (; *format != '\0';)
169*946379e7Schristos     if (*format++ == '%')
170*946379e7Schristos       {
171*946379e7Schristos 	/* A directive.  */
172*946379e7Schristos 	spec.directives++;
173*946379e7Schristos 
174*946379e7Schristos 	if (*format == '%' || *format == '<' || *format == '>'
175*946379e7Schristos 	    || *format == '\'')
176*946379e7Schristos 	  ;
177*946379e7Schristos 	else if (*format == 'm')
178*946379e7Schristos 	  spec.uses_err_no = true;
179*946379e7Schristos 	else
180*946379e7Schristos 	  {
181*946379e7Schristos 	    unsigned int number = 0;
182*946379e7Schristos 	    unsigned int flag_q = 0;
183*946379e7Schristos 	    unsigned int flag_l = 0;
184*946379e7Schristos 	    unsigned int flag_w = 0;
185*946379e7Schristos 	    unsigned int flag_plus = 0;
186*946379e7Schristos 	    unsigned int flag_sharp = 0;
187*946379e7Schristos 	    enum format_arg_type size;
188*946379e7Schristos 	    enum format_arg_type type;
189*946379e7Schristos 
190*946379e7Schristos 	    if (isdigit (*format))
191*946379e7Schristos 	      {
192*946379e7Schristos 		const char *f = format;
193*946379e7Schristos 		unsigned int m = 0;
194*946379e7Schristos 
195*946379e7Schristos 		do
196*946379e7Schristos 		  {
197*946379e7Schristos 		    m = 10 * m + (*f - '0');
198*946379e7Schristos 		    f++;
199*946379e7Schristos 		  }
200*946379e7Schristos 		while (isdigit (*f));
201*946379e7Schristos 
202*946379e7Schristos 		if (*f == '$')
203*946379e7Schristos 		  {
204*946379e7Schristos 		    if (m == 0)
205*946379e7Schristos 		      {
206*946379e7Schristos 			*invalid_reason = INVALID_ARGNO_0 (spec.directives);
207*946379e7Schristos 			goto bad_format;
208*946379e7Schristos 		      }
209*946379e7Schristos 		    number = m;
210*946379e7Schristos 		    format = ++f;
211*946379e7Schristos 		  }
212*946379e7Schristos 	      }
213*946379e7Schristos 
214*946379e7Schristos 	    /* Parse flags and size.  */
215*946379e7Schristos 	    for (;; format++)
216*946379e7Schristos 	      {
217*946379e7Schristos 		switch (*format)
218*946379e7Schristos 		  {
219*946379e7Schristos 		  case 'q':
220*946379e7Schristos 		    if (flag_q > 0)
221*946379e7Schristos 		      goto invalid_flags;
222*946379e7Schristos 		    flag_q = 1;
223*946379e7Schristos 		    continue;
224*946379e7Schristos 		  case 'l':
225*946379e7Schristos 		    if (flag_l > 1 || flag_w)
226*946379e7Schristos 		      goto invalid_flags;
227*946379e7Schristos 		    flag_l++;
228*946379e7Schristos 		    continue;
229*946379e7Schristos 		  case 'w':
230*946379e7Schristos 		    if (flag_w > 0 || flag_l)
231*946379e7Schristos 		      goto invalid_flags;
232*946379e7Schristos 		    flag_w = 1;
233*946379e7Schristos 		    continue;
234*946379e7Schristos 		  case '+':
235*946379e7Schristos 		    if (flag_plus > 0)
236*946379e7Schristos 		      goto invalid_flags;
237*946379e7Schristos 		    flag_plus = 1;
238*946379e7Schristos 		    continue;
239*946379e7Schristos 		  case '#':
240*946379e7Schristos 		    if (flag_sharp > 0)
241*946379e7Schristos 		      goto invalid_flags;
242*946379e7Schristos 		    flag_sharp = 1;
243*946379e7Schristos 		    continue;
244*946379e7Schristos 		  invalid_flags:
245*946379e7Schristos 		    *invalid_reason = xasprintf (_("In the directive number %u, the flags combination is invalid."), spec.directives);
246*946379e7Schristos 		    goto bad_format;
247*946379e7Schristos 		  default:
248*946379e7Schristos 		    break;
249*946379e7Schristos 		  }
250*946379e7Schristos 		break;
251*946379e7Schristos 	      }
252*946379e7Schristos 	    size = (flag_l == 2 ? FAT_SIZE_LONGLONG :
253*946379e7Schristos 		    flag_l == 1 ? FAT_SIZE_LONG :
254*946379e7Schristos 		    flag_w ? FAT_SIZE_WIDE :
255*946379e7Schristos 		    0);
256*946379e7Schristos 
257*946379e7Schristos 	    if (*format == 'c')
258*946379e7Schristos 	      type = FAT_CHAR;
259*946379e7Schristos 	    else if (*format == 's')
260*946379e7Schristos 	      type = FAT_STRING;
261*946379e7Schristos 	    else if (*format == '.')
262*946379e7Schristos 	      {
263*946379e7Schristos 		format++;
264*946379e7Schristos 
265*946379e7Schristos 		if (isdigit (*format))
266*946379e7Schristos 		  {
267*946379e7Schristos 		    do
268*946379e7Schristos 		      format++;
269*946379e7Schristos 		    while (isdigit (*format));
270*946379e7Schristos 
271*946379e7Schristos 		    if (*format != 's')
272*946379e7Schristos 		      {
273*946379e7Schristos 			*invalid_reason =
274*946379e7Schristos 			  (*format == '\0'
275*946379e7Schristos 			   ? INVALID_UNTERMINATED_DIRECTIVE ()
276*946379e7Schristos 			   : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
277*946379e7Schristos 			goto bad_format;
278*946379e7Schristos 		      }
279*946379e7Schristos 
280*946379e7Schristos 		    type = FAT_STRING;
281*946379e7Schristos 		  }
282*946379e7Schristos 		else if (*format == '*')
283*946379e7Schristos 		  {
284*946379e7Schristos 		    unsigned int precision_number = 0;
285*946379e7Schristos 
286*946379e7Schristos 		    format++;
287*946379e7Schristos 
288*946379e7Schristos 		    if (isdigit (*format))
289*946379e7Schristos 		      {
290*946379e7Schristos 			const char *f = format;
291*946379e7Schristos 			unsigned int m = 0;
292*946379e7Schristos 
293*946379e7Schristos 			do
294*946379e7Schristos 			  {
295*946379e7Schristos 			    m = 10 * m + (*f - '0');
296*946379e7Schristos 			    f++;
297*946379e7Schristos 			  }
298*946379e7Schristos 			while (isdigit (*f));
299*946379e7Schristos 
300*946379e7Schristos 			if (*f == '$')
301*946379e7Schristos 			  {
302*946379e7Schristos 			    if (m == 0)
303*946379e7Schristos 			      {
304*946379e7Schristos 				*invalid_reason = INVALID_WIDTH_ARGNO_0 (spec.directives);
305*946379e7Schristos 				goto bad_format;
306*946379e7Schristos 			      }
307*946379e7Schristos 			    if (unnumbered_arg_count > 0 || number == 0)
308*946379e7Schristos 			      {
309*946379e7Schristos 				*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
310*946379e7Schristos 				goto bad_format;
311*946379e7Schristos 			      }
312*946379e7Schristos 			    if (m != number - 1)
313*946379e7Schristos 			      {
314*946379e7Schristos 				*invalid_reason = xasprintf (_("In the directive number %u, the argument number for the precision must be equal to %u."), spec.directives, number - 1);
315*946379e7Schristos 				goto bad_format;
316*946379e7Schristos 			      }
317*946379e7Schristos 			    precision_number = m;
318*946379e7Schristos 			    format = ++f;
319*946379e7Schristos 			  }
320*946379e7Schristos 		      }
321*946379e7Schristos 
322*946379e7Schristos 		    if (precision_number)
323*946379e7Schristos 		      {
324*946379e7Schristos 			/* Numbered argument.  */
325*946379e7Schristos 
326*946379e7Schristos 			/* Numbered and unnumbered specifications are exclusive.  */
327*946379e7Schristos 			if (unnumbered_arg_count > 0)
328*946379e7Schristos 			  {
329*946379e7Schristos 			    *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
330*946379e7Schristos 			    goto bad_format;
331*946379e7Schristos 			  }
332*946379e7Schristos 
333*946379e7Schristos 			if (spec.allocated == spec.numbered_arg_count)
334*946379e7Schristos 			  {
335*946379e7Schristos 			    spec.allocated = 2 * spec.allocated + 1;
336*946379e7Schristos 			    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
337*946379e7Schristos 			  }
338*946379e7Schristos 			spec.numbered[spec.numbered_arg_count].number = precision_number;
339*946379e7Schristos 			spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
340*946379e7Schristos 			spec.numbered_arg_count++;
341*946379e7Schristos 		      }
342*946379e7Schristos 		    else
343*946379e7Schristos 		      {
344*946379e7Schristos 			/* Unnumbered argument.  */
345*946379e7Schristos 
346*946379e7Schristos 			/* Numbered and unnumbered specifications are exclusive.  */
347*946379e7Schristos 			if (spec.numbered_arg_count > 0)
348*946379e7Schristos 			  {
349*946379e7Schristos 			    *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
350*946379e7Schristos 			    goto bad_format;
351*946379e7Schristos 			  }
352*946379e7Schristos 
353*946379e7Schristos 			if (spec.allocated == unnumbered_arg_count)
354*946379e7Schristos 			  {
355*946379e7Schristos 			    spec.allocated = 2 * spec.allocated + 1;
356*946379e7Schristos 			    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
357*946379e7Schristos 			  }
358*946379e7Schristos 			spec.numbered[unnumbered_arg_count].number = unnumbered_arg_count + 1;
359*946379e7Schristos 			spec.numbered[unnumbered_arg_count].type = FAT_INTEGER;
360*946379e7Schristos 			unnumbered_arg_count++;
361*946379e7Schristos 		      }
362*946379e7Schristos 
363*946379e7Schristos 		    if (*format == 's')
364*946379e7Schristos 		      type = FAT_STRING;
365*946379e7Schristos 		    else
366*946379e7Schristos 		      {
367*946379e7Schristos 			*invalid_reason =
368*946379e7Schristos 			  (*format == '\0'
369*946379e7Schristos 			   ? INVALID_UNTERMINATED_DIRECTIVE ()
370*946379e7Schristos 			   : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
371*946379e7Schristos 			goto bad_format;
372*946379e7Schristos 		      }
373*946379e7Schristos 		  }
374*946379e7Schristos 		else
375*946379e7Schristos 		  {
376*946379e7Schristos 		    *invalid_reason = xasprintf (_("In the directive number %u, the precision specification is invalid."), spec.directives);
377*946379e7Schristos 		    goto bad_format;
378*946379e7Schristos 		  }
379*946379e7Schristos 	      }
380*946379e7Schristos 	    else if (*format == 'i' || *format == 'd')
381*946379e7Schristos 	      type = FAT_INTEGER | size;
382*946379e7Schristos 	    else if (*format == 'o' || *format == 'u' || *format == 'x')
383*946379e7Schristos 	      type = FAT_INTEGER | FAT_UNSIGNED | size;
384*946379e7Schristos 	    else if (*format == 'p')
385*946379e7Schristos 	      type = FAT_POINTER;
386*946379e7Schristos 	    else if (*format == 'H')
387*946379e7Schristos 	      type = FAT_LOCATION;
388*946379e7Schristos 	    else if (*format == 'J')
389*946379e7Schristos 	      type = FAT_TREE | FAT_TREE_DECL;
390*946379e7Schristos 	    else
391*946379e7Schristos 	      {
392*946379e7Schristos 		if (*format == 'D')
393*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_DECL;
394*946379e7Schristos 		else if (*format == 'F')
395*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_FUNCDECL;
396*946379e7Schristos 		else if (*format == 'T')
397*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_TYPE;
398*946379e7Schristos 		else if (*format == 'E')
399*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_EXPRESSION;
400*946379e7Schristos 		else if (*format == 'A')
401*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_ARGUMENT;
402*946379e7Schristos 		else if (*format == 'C')
403*946379e7Schristos 		  type = FAT_TREE_CODE;
404*946379e7Schristos 		else if (*format == 'L')
405*946379e7Schristos 		  type = FAT_LANGUAGES;
406*946379e7Schristos 		else if (*format == 'O')
407*946379e7Schristos 		  type = FAT_TREE_CODE | FAT_TREE_CODE_BINOP;
408*946379e7Schristos 		else if (*format == 'P')
409*946379e7Schristos 		  type = FAT_INTEGER | FAT_FUNCPARAM;
410*946379e7Schristos 		else if (*format == 'Q')
411*946379e7Schristos 		  type = FAT_TREE_CODE | FAT_TREE_CODE_ASSOP;
412*946379e7Schristos 		else if (*format == 'V')
413*946379e7Schristos 		  type = FAT_TREE | FAT_TREE_CV;
414*946379e7Schristos 		else
415*946379e7Schristos 		  {
416*946379e7Schristos 		    *invalid_reason =
417*946379e7Schristos 		      (*format == '\0'
418*946379e7Schristos 		       ? INVALID_UNTERMINATED_DIRECTIVE ()
419*946379e7Schristos 		       : (*format == 'c'
420*946379e7Schristos 			  || *format == 's'
421*946379e7Schristos 			  || *format == 'i' || *format == 'd'
422*946379e7Schristos 			  || *format == 'o' || *format == 'u' || *format == 'x'
423*946379e7Schristos 			  || *format == 'H'
424*946379e7Schristos 			  ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec.directives, *format)
425*946379e7Schristos 			  : INVALID_CONVERSION_SPECIFIER (spec.directives,
426*946379e7Schristos 							  *format)));
427*946379e7Schristos 		    goto bad_format;
428*946379e7Schristos 		  }
429*946379e7Schristos 	      }
430*946379e7Schristos 
431*946379e7Schristos 	    if (number)
432*946379e7Schristos 	      {
433*946379e7Schristos 		/* Numbered argument.  */
434*946379e7Schristos 
435*946379e7Schristos 		/* Numbered and unnumbered specifications are exclusive.  */
436*946379e7Schristos 		if (unnumbered_arg_count > 0)
437*946379e7Schristos 		  {
438*946379e7Schristos 		    *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
439*946379e7Schristos 		    goto bad_format;
440*946379e7Schristos 		  }
441*946379e7Schristos 
442*946379e7Schristos 		if (spec.allocated == spec.numbered_arg_count)
443*946379e7Schristos 		  {
444*946379e7Schristos 		    spec.allocated = 2 * spec.allocated + 1;
445*946379e7Schristos 		    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
446*946379e7Schristos 		  }
447*946379e7Schristos 		spec.numbered[spec.numbered_arg_count].number = number;
448*946379e7Schristos 		spec.numbered[spec.numbered_arg_count].type = type;
449*946379e7Schristos 		spec.numbered_arg_count++;
450*946379e7Schristos 	      }
451*946379e7Schristos 	    else
452*946379e7Schristos 	      {
453*946379e7Schristos 		/* Unnumbered argument.  */
454*946379e7Schristos 
455*946379e7Schristos 		/* Numbered and unnumbered specifications are exclusive.  */
456*946379e7Schristos 		if (spec.numbered_arg_count > 0)
457*946379e7Schristos 		  {
458*946379e7Schristos 		    *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
459*946379e7Schristos 		    goto bad_format;
460*946379e7Schristos 		  }
461*946379e7Schristos 
462*946379e7Schristos 		if (spec.allocated == unnumbered_arg_count)
463*946379e7Schristos 		  {
464*946379e7Schristos 		    spec.allocated = 2 * spec.allocated + 1;
465*946379e7Schristos 		    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
466*946379e7Schristos 		  }
467*946379e7Schristos 		spec.numbered[unnumbered_arg_count].number = unnumbered_arg_count + 1;
468*946379e7Schristos 		spec.numbered[unnumbered_arg_count].type = type;
469*946379e7Schristos 		unnumbered_arg_count++;
470*946379e7Schristos 	      }
471*946379e7Schristos 	  }
472*946379e7Schristos 
473*946379e7Schristos 	format++;
474*946379e7Schristos       }
475*946379e7Schristos 
476*946379e7Schristos   /* Convert the unnumbered argument array to numbered arguments.  */
477*946379e7Schristos   if (unnumbered_arg_count > 0)
478*946379e7Schristos     spec.numbered_arg_count = unnumbered_arg_count;
479*946379e7Schristos   /* Sort the numbered argument array, and eliminate duplicates.  */
480*946379e7Schristos   else if (spec.numbered_arg_count > 1)
481*946379e7Schristos     {
482*946379e7Schristos       unsigned int i, j;
483*946379e7Schristos       bool err;
484*946379e7Schristos 
485*946379e7Schristos       qsort (spec.numbered, spec.numbered_arg_count,
486*946379e7Schristos 	     sizeof (struct numbered_arg), numbered_arg_compare);
487*946379e7Schristos 
488*946379e7Schristos       /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
489*946379e7Schristos       err = false;
490*946379e7Schristos       for (i = j = 0; i < spec.numbered_arg_count; i++)
491*946379e7Schristos 	if (j > 0 && spec.numbered[i].number == spec.numbered[j-1].number)
492*946379e7Schristos 	  {
493*946379e7Schristos 	    enum format_arg_type type1 = spec.numbered[i].type;
494*946379e7Schristos 	    enum format_arg_type type2 = spec.numbered[j-1].type;
495*946379e7Schristos 	    enum format_arg_type type_both;
496*946379e7Schristos 
497*946379e7Schristos 	    if (type1 == type2)
498*946379e7Schristos 	      type_both = type1;
499*946379e7Schristos 	    else
500*946379e7Schristos 	      {
501*946379e7Schristos 		/* Incompatible types.  */
502*946379e7Schristos 		type_both = FAT_NONE;
503*946379e7Schristos 		if (!err)
504*946379e7Schristos 		  *invalid_reason =
505*946379e7Schristos 		    INVALID_INCOMPATIBLE_ARG_TYPES (spec.numbered[i].number);
506*946379e7Schristos 		err = true;
507*946379e7Schristos 	      }
508*946379e7Schristos 
509*946379e7Schristos 	    spec.numbered[j-1].type = type_both;
510*946379e7Schristos 	  }
511*946379e7Schristos 	else
512*946379e7Schristos 	  {
513*946379e7Schristos 	    if (j < i)
514*946379e7Schristos 	      {
515*946379e7Schristos 		spec.numbered[j].number = spec.numbered[i].number;
516*946379e7Schristos 		spec.numbered[j].type = spec.numbered[i].type;
517*946379e7Schristos 	      }
518*946379e7Schristos 	    j++;
519*946379e7Schristos 	  }
520*946379e7Schristos       spec.numbered_arg_count = j;
521*946379e7Schristos       if (err)
522*946379e7Schristos 	/* *invalid_reason has already been set above.  */
523*946379e7Schristos 	goto bad_format;
524*946379e7Schristos     }
525*946379e7Schristos 
526*946379e7Schristos   result = (struct spec *) xmalloc (sizeof (struct spec));
527*946379e7Schristos   *result = spec;
528*946379e7Schristos   return result;
529*946379e7Schristos 
530*946379e7Schristos  bad_format:
531*946379e7Schristos   if (spec.numbered != NULL)
532*946379e7Schristos     free (spec.numbered);
533*946379e7Schristos   return NULL;
534*946379e7Schristos }
535*946379e7Schristos 
536*946379e7Schristos static void
format_free(void * descr)537*946379e7Schristos format_free (void *descr)
538*946379e7Schristos {
539*946379e7Schristos   struct spec *spec = (struct spec *) descr;
540*946379e7Schristos 
541*946379e7Schristos   if (spec->numbered != NULL)
542*946379e7Schristos     free (spec->numbered);
543*946379e7Schristos   free (spec);
544*946379e7Schristos }
545*946379e7Schristos 
546*946379e7Schristos static int
format_get_number_of_directives(void * descr)547*946379e7Schristos format_get_number_of_directives (void *descr)
548*946379e7Schristos {
549*946379e7Schristos   struct spec *spec = (struct spec *) descr;
550*946379e7Schristos 
551*946379e7Schristos   return spec->directives;
552*946379e7Schristos }
553*946379e7Schristos 
554*946379e7Schristos static bool
format_check(void * msgid_descr,void * msgstr_descr,bool equality,formatstring_error_logger_t error_logger,const char * pretty_msgstr)555*946379e7Schristos format_check (void *msgid_descr, void *msgstr_descr, bool equality,
556*946379e7Schristos 	      formatstring_error_logger_t error_logger,
557*946379e7Schristos 	      const char *pretty_msgstr)
558*946379e7Schristos {
559*946379e7Schristos   struct spec *spec1 = (struct spec *) msgid_descr;
560*946379e7Schristos   struct spec *spec2 = (struct spec *) msgstr_descr;
561*946379e7Schristos   bool err = false;
562*946379e7Schristos 
563*946379e7Schristos   if (spec1->numbered_arg_count + spec2->numbered_arg_count > 0)
564*946379e7Schristos     {
565*946379e7Schristos       unsigned int i, j;
566*946379e7Schristos       unsigned int n1 = spec1->numbered_arg_count;
567*946379e7Schristos       unsigned int n2 = spec2->numbered_arg_count;
568*946379e7Schristos 
569*946379e7Schristos       /* Check the argument names are the same.
570*946379e7Schristos 	 Both arrays are sorted.  We search for the first difference.  */
571*946379e7Schristos       for (i = 0, j = 0; i < n1 || j < n2; )
572*946379e7Schristos 	{
573*946379e7Schristos 	  int cmp = (i >= n1 ? 1 :
574*946379e7Schristos 		     j >= n2 ? -1 :
575*946379e7Schristos 		     spec1->numbered[i].number > spec2->numbered[j].number ? 1 :
576*946379e7Schristos 		     spec1->numbered[i].number < spec2->numbered[j].number ? -1 :
577*946379e7Schristos 		     0);
578*946379e7Schristos 
579*946379e7Schristos 	  if (cmp > 0)
580*946379e7Schristos 	    {
581*946379e7Schristos 	      if (error_logger)
582*946379e7Schristos 		error_logger (_("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"),
583*946379e7Schristos 			      spec2->numbered[j].number, pretty_msgstr);
584*946379e7Schristos 	      err = true;
585*946379e7Schristos 	      break;
586*946379e7Schristos 	    }
587*946379e7Schristos 	  else if (cmp < 0)
588*946379e7Schristos 	    {
589*946379e7Schristos 	      if (equality)
590*946379e7Schristos 		{
591*946379e7Schristos 		  if (error_logger)
592*946379e7Schristos 		    error_logger (_("a format specification for argument %u doesn't exist in '%s'"),
593*946379e7Schristos 				  spec1->numbered[i].number, pretty_msgstr);
594*946379e7Schristos 		  err = true;
595*946379e7Schristos 		  break;
596*946379e7Schristos 		}
597*946379e7Schristos 	      else
598*946379e7Schristos 		i++;
599*946379e7Schristos 	    }
600*946379e7Schristos 	  else
601*946379e7Schristos 	    j++, i++;
602*946379e7Schristos 	}
603*946379e7Schristos       /* Check the argument types are the same.  */
604*946379e7Schristos       if (!err)
605*946379e7Schristos 	for (i = 0, j = 0; j < n2; )
606*946379e7Schristos 	  {
607*946379e7Schristos 	    if (spec1->numbered[i].number == spec2->numbered[j].number)
608*946379e7Schristos 	      {
609*946379e7Schristos 		if (spec1->numbered[i].type != spec2->numbered[j].type)
610*946379e7Schristos 		  {
611*946379e7Schristos 		    if (error_logger)
612*946379e7Schristos 		      error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"),
613*946379e7Schristos 				    pretty_msgstr, spec2->numbered[j].number);
614*946379e7Schristos 		    err = true;
615*946379e7Schristos 		    break;
616*946379e7Schristos 		  }
617*946379e7Schristos 		j++, i++;
618*946379e7Schristos 	      }
619*946379e7Schristos 	    else
620*946379e7Schristos 	      i++;
621*946379e7Schristos 	  }
622*946379e7Schristos     }
623*946379e7Schristos 
624*946379e7Schristos   /* Check that the use of err_no is the same.  */
625*946379e7Schristos   if (spec1->uses_err_no != spec2->uses_err_no)
626*946379e7Schristos     {
627*946379e7Schristos       if (error_logger)
628*946379e7Schristos 	{
629*946379e7Schristos 	  if (spec1->uses_err_no)
630*946379e7Schristos 	    error_logger (_("'msgid' uses %%m but '%s' doesn't"),
631*946379e7Schristos 			  pretty_msgstr);
632*946379e7Schristos 	  else
633*946379e7Schristos 	    error_logger (_("'msgid' does not use %%m but '%s' uses %%m"),
634*946379e7Schristos 			  pretty_msgstr);
635*946379e7Schristos 	}
636*946379e7Schristos       err = true;
637*946379e7Schristos     }
638*946379e7Schristos 
639*946379e7Schristos   return err;
640*946379e7Schristos }
641*946379e7Schristos 
642*946379e7Schristos 
643*946379e7Schristos struct formatstring_parser formatstring_gcc_internal =
644*946379e7Schristos {
645*946379e7Schristos   format_parse,
646*946379e7Schristos   format_free,
647*946379e7Schristos   format_get_number_of_directives,
648*946379e7Schristos   NULL,
649*946379e7Schristos   format_check
650*946379e7Schristos };
651*946379e7Schristos 
652*946379e7Schristos 
653*946379e7Schristos #ifdef TEST
654*946379e7Schristos 
655*946379e7Schristos /* Test program: Print the argument list specification returned by
656*946379e7Schristos    format_parse for strings read from standard input.  */
657*946379e7Schristos 
658*946379e7Schristos #include <stdio.h>
659*946379e7Schristos #include "getline.h"
660*946379e7Schristos 
661*946379e7Schristos static void
format_print(void * descr)662*946379e7Schristos format_print (void *descr)
663*946379e7Schristos {
664*946379e7Schristos   struct spec *spec = (struct spec *) descr;
665*946379e7Schristos   unsigned int last;
666*946379e7Schristos   unsigned int i;
667*946379e7Schristos 
668*946379e7Schristos   if (spec == NULL)
669*946379e7Schristos     {
670*946379e7Schristos       printf ("INVALID");
671*946379e7Schristos       return;
672*946379e7Schristos     }
673*946379e7Schristos 
674*946379e7Schristos   printf ("(");
675*946379e7Schristos   last = 1;
676*946379e7Schristos   for (i = 0; i < spec->numbered_arg_count; i++)
677*946379e7Schristos     {
678*946379e7Schristos       unsigned int number = spec->numbered[i].number;
679*946379e7Schristos 
680*946379e7Schristos       if (i > 0)
681*946379e7Schristos 	printf (" ");
682*946379e7Schristos       if (number < last)
683*946379e7Schristos 	abort ();
684*946379e7Schristos       for (; last < number; last++)
685*946379e7Schristos 	printf ("_ ");
686*946379e7Schristos       if (spec->numbered[i].type & FAT_UNSIGNED)
687*946379e7Schristos 	printf ("[unsigned]");
688*946379e7Schristos       switch (spec->numbered[i].type & FAT_SIZE_MASK)
689*946379e7Schristos 	{
690*946379e7Schristos 	case 0:
691*946379e7Schristos 	  break;
692*946379e7Schristos 	case FAT_SIZE_LONG:
693*946379e7Schristos 	  printf ("[long]");
694*946379e7Schristos 	  break;
695*946379e7Schristos 	case FAT_SIZE_LONGLONG:
696*946379e7Schristos 	  printf ("[long long]");
697*946379e7Schristos 	  break;
698*946379e7Schristos 	case FAT_SIZE_WIDE:
699*946379e7Schristos 	  printf ("[host-wide]");
700*946379e7Schristos 	  break;
701*946379e7Schristos 	default:
702*946379e7Schristos 	  abort ();
703*946379e7Schristos 	}
704*946379e7Schristos       switch (spec->numbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_MASK))
705*946379e7Schristos 	{
706*946379e7Schristos 	case FAT_INTEGER:
707*946379e7Schristos 	  printf ("i");
708*946379e7Schristos 	  break;
709*946379e7Schristos 	case FAT_INTEGER | FAT_FUNCPARAM:
710*946379e7Schristos 	  printf ("P");
711*946379e7Schristos 	  break;
712*946379e7Schristos 	case FAT_CHAR:
713*946379e7Schristos 	  printf ("c");
714*946379e7Schristos 	  break;
715*946379e7Schristos 	case FAT_STRING:
716*946379e7Schristos 	  printf ("s");
717*946379e7Schristos 	  break;
718*946379e7Schristos 	case FAT_POINTER:
719*946379e7Schristos 	  printf ("p");
720*946379e7Schristos 	  break;
721*946379e7Schristos 	case FAT_LOCATION:
722*946379e7Schristos 	  printf ("H");
723*946379e7Schristos 	  break;
724*946379e7Schristos 	case FAT_TREE | FAT_TREE_DECL:
725*946379e7Schristos 	  printf ("D");
726*946379e7Schristos 	  break;
727*946379e7Schristos 	case FAT_TREE | FAT_TREE_FUNCDECL:
728*946379e7Schristos 	  printf ("F");
729*946379e7Schristos 	  break;
730*946379e7Schristos 	case FAT_TREE | FAT_TREE_TYPE:
731*946379e7Schristos 	  printf ("T");
732*946379e7Schristos 	  break;
733*946379e7Schristos 	case FAT_TREE | FAT_TREE_ARGUMENT:
734*946379e7Schristos 	  printf ("A");
735*946379e7Schristos 	  break;
736*946379e7Schristos 	case FAT_TREE | FAT_TREE_EXPRESSION:
737*946379e7Schristos 	  printf ("E");
738*946379e7Schristos 	  break;
739*946379e7Schristos 	case FAT_TREE | FAT_TREE_CV:
740*946379e7Schristos 	  printf ("V");
741*946379e7Schristos 	  break;
742*946379e7Schristos 	case FAT_TREE_CODE:
743*946379e7Schristos 	  printf ("C");
744*946379e7Schristos 	  break;
745*946379e7Schristos 	case FAT_TREE_CODE | FAT_TREE_CODE_BINOP:
746*946379e7Schristos 	  printf ("O");
747*946379e7Schristos 	  break;
748*946379e7Schristos 	case FAT_TREE_CODE | FAT_TREE_CODE_ASSOP:
749*946379e7Schristos 	  printf ("Q");
750*946379e7Schristos 	  break;
751*946379e7Schristos 	case FAT_LANGUAGES:
752*946379e7Schristos 	  printf ("L");
753*946379e7Schristos 	  break;
754*946379e7Schristos 	default:
755*946379e7Schristos 	  abort ();
756*946379e7Schristos 	}
757*946379e7Schristos       last = number + 1;
758*946379e7Schristos     }
759*946379e7Schristos   printf (")");
760*946379e7Schristos   if (spec->uses_err_no)
761*946379e7Schristos     printf (" ERR_NO");
762*946379e7Schristos }
763*946379e7Schristos 
764*946379e7Schristos int
main()765*946379e7Schristos main ()
766*946379e7Schristos {
767*946379e7Schristos   for (;;)
768*946379e7Schristos     {
769*946379e7Schristos       char *line = NULL;
770*946379e7Schristos       size_t line_size = 0;
771*946379e7Schristos       int line_len;
772*946379e7Schristos       char *invalid_reason;
773*946379e7Schristos       void *descr;
774*946379e7Schristos 
775*946379e7Schristos       line_len = getline (&line, &line_size, stdin);
776*946379e7Schristos       if (line_len < 0)
777*946379e7Schristos 	break;
778*946379e7Schristos       if (line_len > 0 && line[line_len - 1] == '\n')
779*946379e7Schristos 	line[--line_len] = '\0';
780*946379e7Schristos 
781*946379e7Schristos       invalid_reason = NULL;
782*946379e7Schristos       descr = format_parse (line, false, &invalid_reason);
783*946379e7Schristos 
784*946379e7Schristos       format_print (descr);
785*946379e7Schristos       printf ("\n");
786*946379e7Schristos       if (descr == NULL)
787*946379e7Schristos 	printf ("%s\n", invalid_reason);
788*946379e7Schristos 
789*946379e7Schristos       free (invalid_reason);
790*946379e7Schristos       free (line);
791*946379e7Schristos     }
792*946379e7Schristos 
793*946379e7Schristos   return 0;
794*946379e7Schristos }
795*946379e7Schristos 
796*946379e7Schristos /*
797*946379e7Schristos  * For Emacs M-x compile
798*946379e7Schristos  * Local Variables:
799*946379e7Schristos  * compile-command: "/bin/sh ../libtool --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../lib -I../intl -DHAVE_CONFIG_H -DTEST format-gcc-internal.c ../lib/libgettextlib.la"
800*946379e7Schristos  * End:
801*946379e7Schristos  */
802*946379e7Schristos 
803*946379e7Schristos #endif /* TEST */
804