1 /* GCC internal format strings.
2 Copyright (C) 2003-2004 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
30 #include "format-invalid.h"
33 #define _(str) gettext (str)
35 /* GCC internal format strings consist of language frontend independent
36 format directives, implemented in gcc-3.3/gcc/diagnostic.c (function
37 output_format), plus some frontend dependent extensions:
38 - for the C/ObjC frontend in gcc-3.3/gcc/c-objc-common.c
39 - for the C++ frontend in gcc-3.3/gcc/cp/error.c
40 Taking these together, GCC internal format strings are specified as follows.
43 - is optionally followed by a size specifier 'l',
44 - is optionally followed by '+' (only the specifiers of gcc/cp/error.c),
45 - is optionally followed by '#' (only the specifiers of gcc/cp/error.c),
46 - is finished by a specifier
48 - '%', that needs no argument,
49 - 'c', that needs a character argument,
50 - 's', that needs a string argument,
51 - 'i', 'd', that need a signed integer argument,
52 - 'o', 'u', 'x', that need an unsigned integer argument,
53 - '.*s', that needs a signed integer argument and a string argument,
54 - 'H', that needs a 'location_t *' argument,
55 [see gcc/diagnostic.c]
57 - 'D', that needs a general declaration argument,
58 - 'F', that needs a function declaration argument,
59 - 'T', that needs a type argument,
60 [see gcc/c-objc-common.c and gcc/cp/error.c]
62 - 'A', that needs a function argument list argument,
63 - 'C', that needs a tree code argument,
64 - 'E', that needs an expression argument,
65 - 'L', that needs a language argument,
66 - 'O', that needs a binary operator argument,
67 - 'P', that needs a function parameter argument,
68 - 'Q', that needs an assignment operator argument,
69 - 'V', that needs a const/volatile qualifier argument.
85 FAT_UNSIGNED
= 1 << 3,
86 FAT_SIZE_LONG
= 1 << 4,
87 FAT_TREE_DECL
= 1 << 5,
88 FAT_TREE_FUNCDECL
= 2 << 5,
89 FAT_TREE_TYPE
= 3 << 5,
90 FAT_TREE_ARGUMENT
= 4 << 5,
91 FAT_TREE_EXPRESSION
= 5 << 5,
93 FAT_TREE_CODE_BINOP
= 1 << 8,
94 FAT_TREE_CODE_ASSOP
= 2 << 8,
95 FAT_FUNCPARAM
= 1 << 10
100 enum format_arg_type type
;
105 unsigned int directives
;
106 unsigned int unnumbered_arg_count
;
107 unsigned int allocated
;
108 struct unnumbered_arg
*unnumbered
;
113 format_parse (const char *format
, bool translated
, char **invalid_reason
)
119 spec
.unnumbered_arg_count
= 0;
121 spec
.unnumbered
= NULL
;
123 for (; *format
!= '\0';)
124 if (*format
++ == '%')
127 enum format_arg_type size
;
136 size
= FAT_SIZE_LONG
;
141 enum format_arg_type type
;
145 else if (*format
== 's')
147 else if (*format
== 'i' || *format
== 'd')
148 type
= FAT_INTEGER
| size
;
149 else if (*format
== 'o' || *format
== 'u' || *format
== 'x')
150 type
= FAT_INTEGER
| FAT_UNSIGNED
| size
;
151 else if (*format
== '.' && format
[1] == '*' && format
[2] == 's')
153 if (spec
.allocated
== spec
.unnumbered_arg_count
)
155 spec
.allocated
= 2 * spec
.allocated
+ 1;
156 spec
.unnumbered
= (struct unnumbered_arg
*) xrealloc (spec
.unnumbered
, spec
.allocated
* sizeof (struct unnumbered_arg
));
158 spec
.unnumbered
[spec
.unnumbered_arg_count
].type
= FAT_INTEGER
;
159 spec
.unnumbered_arg_count
++;
162 else if (*format
== 'H')
171 type
= FAT_TREE
| FAT_TREE_DECL
;
172 else if (*format
== 'F')
173 type
= FAT_TREE
| FAT_TREE_FUNCDECL
;
174 else if (*format
== 'T')
175 type
= FAT_TREE
| FAT_TREE_TYPE
;
176 else if (*format
== 'A')
177 type
= FAT_TREE
| FAT_TREE_ARGUMENT
;
178 else if (*format
== 'C')
179 type
= FAT_TREE_CODE
;
180 else if (*format
== 'E')
181 type
= FAT_TREE
| FAT_TREE_EXPRESSION
;
182 else if (*format
== 'L')
183 type
= FAT_LANGUAGES
;
184 else if (*format
== 'O')
185 type
= FAT_TREE_CODE
| FAT_TREE_CODE_BINOP
;
186 else if (*format
== 'P')
187 type
= FAT_INTEGER
| FAT_FUNCPARAM
;
188 else if (*format
== 'Q')
189 type
= FAT_TREE_CODE
| FAT_TREE_CODE_ASSOP
;
190 else if (*format
== 'V')
191 type
= FAT_TREE
| FAT_TREE_CV
;
196 ? INVALID_UNTERMINATED_DIRECTIVE ()
199 || *format
== 'i' || *format
== 'd'
200 || *format
== 'o' || *format
== 'u' || *format
== 'x'
202 ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec
.directives
, *format
)
203 : INVALID_CONVERSION_SPECIFIER (spec
.directives
,
209 if (spec
.allocated
== spec
.unnumbered_arg_count
)
211 spec
.allocated
= 2 * spec
.allocated
+ 1;
212 spec
.unnumbered
= (struct unnumbered_arg
*) xrealloc (spec
.unnumbered
, spec
.allocated
* sizeof (struct unnumbered_arg
));
214 spec
.unnumbered
[spec
.unnumbered_arg_count
].type
= type
;
215 spec
.unnumbered_arg_count
++;
221 result
= (struct spec
*) xmalloc (sizeof (struct spec
));
226 if (spec
.unnumbered
!= NULL
)
227 free (spec
.unnumbered
);
232 format_free (void *descr
)
234 struct spec
*spec
= (struct spec
*) descr
;
236 if (spec
->unnumbered
!= NULL
)
237 free (spec
->unnumbered
);
242 format_get_number_of_directives (void *descr
)
244 struct spec
*spec
= (struct spec
*) descr
;
246 return spec
->directives
;
250 format_check (void *msgid_descr
, void *msgstr_descr
, bool equality
,
251 formatstring_error_logger_t error_logger
,
252 const char *pretty_msgstr
)
254 struct spec
*spec1
= (struct spec
*) msgid_descr
;
255 struct spec
*spec2
= (struct spec
*) msgstr_descr
;
259 /* Check the argument types are the same. */
261 ? spec1
->unnumbered_arg_count
!= spec2
->unnumbered_arg_count
262 : spec1
->unnumbered_arg_count
< spec2
->unnumbered_arg_count
)
265 error_logger (_("number of format specifications in 'msgid' and '%s' does not match"),
270 for (i
= 0; i
< spec2
->unnumbered_arg_count
; i
++)
271 if (spec1
->unnumbered
[i
].type
!= spec2
->unnumbered
[i
].type
)
274 error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"),
275 pretty_msgstr
, i
+ 1);
283 struct formatstring_parser formatstring_gcc_internal
=
287 format_get_number_of_directives
,
294 /* Test program: Print the argument list specification returned by
295 format_parse for strings read from standard input. */
301 format_print (void *descr
)
303 struct spec
*spec
= (struct spec
*) descr
;
313 for (i
= 0; i
< spec
->unnumbered_arg_count
; i
++)
317 if (spec
->unnumbered
[i
].type
& FAT_UNSIGNED
)
318 printf ("[unsigned]");
319 if (spec
->unnumbered
[i
].type
& FAT_SIZE_LONG
)
321 switch (spec
->unnumbered
[i
].type
& ~(FAT_UNSIGNED
| FAT_SIZE_LONG
))
326 case FAT_INTEGER
| FAT_FUNCPARAM
:
338 case FAT_TREE
| FAT_TREE_DECL
:
341 case FAT_TREE
| FAT_TREE_FUNCDECL
:
344 case FAT_TREE
| FAT_TREE_TYPE
:
347 case FAT_TREE
| FAT_TREE_ARGUMENT
:
350 case FAT_TREE
| FAT_TREE_EXPRESSION
:
353 case FAT_TREE
| FAT_TREE_CV
:
359 case FAT_TREE_CODE
| FAT_TREE_CODE_BINOP
:
362 case FAT_TREE_CODE
| FAT_TREE_CODE_ASSOP
:
381 size_t line_size
= 0;
383 char *invalid_reason
;
386 line_len
= getline (&line
, &line_size
, stdin
);
389 if (line_len
> 0 && line
[line_len
- 1] == '\n')
390 line
[--line_len
] = '\0';
392 invalid_reason
= NULL
;
393 descr
= format_parse (line
, false, &invalid_reason
);
395 format_print (descr
);
398 printf ("%s\n", invalid_reason
);
400 free (invalid_reason
);
408 * For Emacs M-x compile
410 * 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"