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