1/* GCC internal format strings. 2 Copyright (C) 2003-2004 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2003. 4 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) 8 any later version. 9 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. 14 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. */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <stdbool.h> 24#include <stdlib.h> 25 26#include "format.h" 27#include "c-ctype.h" 28#include "xalloc.h" 29#include "xerror.h" 30#include "format-invalid.h" 31#include "gettext.h" 32 33#define _(str) gettext (str) 34 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. 41 A directive 42 - starts with '%', 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 47 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] 56 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] 61 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. 70 [see gcc/cp/error.c] 71 */ 72 73enum format_arg_type 74{ 75 FAT_NONE = 0, 76 /* Basic types */ 77 FAT_INTEGER = 1, 78 FAT_CHAR = 2, 79 FAT_STRING = 3, 80 FAT_LOCATION = 4, 81 FAT_TREE = 5, 82 FAT_TREE_CODE = 6, 83 FAT_LANGUAGES = 7, 84 /* Flags */ 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, 92 FAT_TREE_CV = 6 << 5, 93 FAT_TREE_CODE_BINOP = 1 << 8, 94 FAT_TREE_CODE_ASSOP = 2 << 8, 95 FAT_FUNCPARAM = 1 << 10 96}; 97 98struct unnumbered_arg 99{ 100 enum format_arg_type type; 101}; 102 103struct spec 104{ 105 unsigned int directives; 106 unsigned int unnumbered_arg_count; 107 unsigned int allocated; 108 struct unnumbered_arg *unnumbered; 109}; 110 111 112static void * 113format_parse (const char *format, bool translated, char **invalid_reason) 114{ 115 struct spec spec; 116 struct spec *result; 117 118 spec.directives = 0; 119 spec.unnumbered_arg_count = 0; 120 spec.allocated = 0; 121 spec.unnumbered = NULL; 122 123 for (; *format != '\0';) 124 if (*format++ == '%') 125 { 126 /* A directive. */ 127 enum format_arg_type size; 128 129 spec.directives++; 130 131 /* Parse size. */ 132 size = 0; 133 if (*format == 'l') 134 { 135 format++; 136 size = FAT_SIZE_LONG; 137 } 138 139 if (*format != '%') 140 { 141 enum format_arg_type type; 142 143 if (*format == 'c') 144 type = FAT_CHAR; 145 else if (*format == 's') 146 type = FAT_STRING; 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') 152 { 153 if (spec.allocated == spec.unnumbered_arg_count) 154 { 155 spec.allocated = 2 * spec.allocated + 1; 156 spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg)); 157 } 158 spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER; 159 spec.unnumbered_arg_count++; 160 type = FAT_STRING; 161 } 162 else if (*format == 'H') 163 type = FAT_LOCATION; 164 else 165 { 166 if (*format == '+') 167 format++; 168 if (*format == '#') 169 format++; 170 if (*format == 'D') 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; 192 else 193 { 194 *invalid_reason = 195 (*format == '\0' 196 ? INVALID_UNTERMINATED_DIRECTIVE () 197 : (*format == 'c' 198 || *format == 's' 199 || *format == 'i' || *format == 'd' 200 || *format == 'o' || *format == 'u' || *format == 'x' 201 || *format == 'H' 202 ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec.directives, *format) 203 : INVALID_CONVERSION_SPECIFIER (spec.directives, 204 *format))); 205 goto bad_format; 206 } 207 } 208 209 if (spec.allocated == spec.unnumbered_arg_count) 210 { 211 spec.allocated = 2 * spec.allocated + 1; 212 spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg)); 213 } 214 spec.unnumbered[spec.unnumbered_arg_count].type = type; 215 spec.unnumbered_arg_count++; 216 } 217 218 format++; 219 } 220 221 result = (struct spec *) xmalloc (sizeof (struct spec)); 222 *result = spec; 223 return result; 224 225 bad_format: 226 if (spec.unnumbered != NULL) 227 free (spec.unnumbered); 228 return NULL; 229} 230 231static void 232format_free (void *descr) 233{ 234 struct spec *spec = (struct spec *) descr; 235 236 if (spec->unnumbered != NULL) 237 free (spec->unnumbered); 238 free (spec); 239} 240 241static int 242format_get_number_of_directives (void *descr) 243{ 244 struct spec *spec = (struct spec *) descr; 245 246 return spec->directives; 247} 248 249static bool 250format_check (void *msgid_descr, void *msgstr_descr, bool equality, 251 formatstring_error_logger_t error_logger, 252 const char *pretty_msgstr) 253{ 254 struct spec *spec1 = (struct spec *) msgid_descr; 255 struct spec *spec2 = (struct spec *) msgstr_descr; 256 bool err = false; 257 unsigned int i; 258 259 /* Check the argument types are the same. */ 260 if (equality 261 ? spec1->unnumbered_arg_count != spec2->unnumbered_arg_count 262 : spec1->unnumbered_arg_count < spec2->unnumbered_arg_count) 263 { 264 if (error_logger) 265 error_logger (_("number of format specifications in 'msgid' and '%s' does not match"), 266 pretty_msgstr); 267 err = true; 268 } 269 else 270 for (i = 0; i < spec2->unnumbered_arg_count; i++) 271 if (spec1->unnumbered[i].type != spec2->unnumbered[i].type) 272 { 273 if (error_logger) 274 error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"), 275 pretty_msgstr, i + 1); 276 err = true; 277 } 278 279 return err; 280} 281 282 283struct formatstring_parser formatstring_gcc_internal = 284{ 285 format_parse, 286 format_free, 287 format_get_number_of_directives, 288 format_check 289}; 290 291 292#ifdef TEST 293 294/* Test program: Print the argument list specification returned by 295 format_parse for strings read from standard input. */ 296 297#include <stdio.h> 298#include "getline.h" 299 300static void 301format_print (void *descr) 302{ 303 struct spec *spec = (struct spec *) descr; 304 unsigned int i; 305 306 if (spec == NULL) 307 { 308 printf ("INVALID"); 309 return; 310 } 311 312 printf ("("); 313 for (i = 0; i < spec->unnumbered_arg_count; i++) 314 { 315 if (i > 0) 316 printf (" "); 317 if (spec->unnumbered[i].type & FAT_UNSIGNED) 318 printf ("[unsigned]"); 319 if (spec->unnumbered[i].type & FAT_SIZE_LONG) 320 printf ("[long]"); 321 switch (spec->unnumbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_LONG)) 322 { 323 case FAT_INTEGER: 324 printf ("i"); 325 break; 326 case FAT_INTEGER | FAT_FUNCPARAM: 327 printf ("P"); 328 break; 329 case FAT_CHAR: 330 printf ("c"); 331 break; 332 case FAT_STRING: 333 printf ("s"); 334 break; 335 case FAT_LOCATION: 336 printf ("H"); 337 break; 338 case FAT_TREE | FAT_TREE_DECL: 339 printf ("D"); 340 break; 341 case FAT_TREE | FAT_TREE_FUNCDECL: 342 printf ("F"); 343 break; 344 case FAT_TREE | FAT_TREE_TYPE: 345 printf ("T"); 346 break; 347 case FAT_TREE | FAT_TREE_ARGUMENT: 348 printf ("A"); 349 break; 350 case FAT_TREE | FAT_TREE_EXPRESSION: 351 printf ("E"); 352 break; 353 case FAT_TREE | FAT_TREE_CV: 354 printf ("V"); 355 break; 356 case FAT_TREE_CODE: 357 printf ("C"); 358 break; 359 case FAT_TREE_CODE | FAT_TREE_CODE_BINOP: 360 printf ("O"); 361 break; 362 case FAT_TREE_CODE | FAT_TREE_CODE_ASSOP: 363 printf ("Q"); 364 break; 365 case FAT_LANGUAGES: 366 printf ("L"); 367 break; 368 default: 369 abort (); 370 } 371 } 372 printf (")"); 373} 374 375int 376main () 377{ 378 for (;;) 379 { 380 char *line = NULL; 381 size_t line_size = 0; 382 int line_len; 383 char *invalid_reason; 384 void *descr; 385 386 line_len = getline (&line, &line_size, stdin); 387 if (line_len < 0) 388 break; 389 if (line_len > 0 && line[line_len - 1] == '\n') 390 line[--line_len] = '\0'; 391 392 invalid_reason = NULL; 393 descr = format_parse (line, false, &invalid_reason); 394 395 format_print (descr); 396 printf ("\n"); 397 if (descr == NULL) 398 printf ("%s\n", invalid_reason); 399 400 free (invalid_reason); 401 free (line); 402 } 403 404 return 0; 405} 406 407/* 408 * For Emacs M-x compile 409 * Local Variables: 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" 411 * End: 412 */ 413 414#endif /* TEST */ 415