xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/format-gcc-internal.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /* GCC internal format strings.
2    Copyright (C) 2003-2006 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., 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
numbered_arg_compare(const void * p1,const void * p2)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 *
format_parse(const char * format,bool translated,char ** invalid_reason)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
format_free(void * descr)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
format_get_number_of_directives(void * descr)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
format_check(void * msgid_descr,void * msgstr_descr,bool equality,formatstring_error_logger_t error_logger,const char * pretty_msgstr)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
format_print(void * descr)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
main()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