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