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
93enum 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
123struct numbered_arg
124{
125  unsigned int number;
126  enum format_arg_type type;
127};
128
129struct 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
145static int
146numbered_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
154static void *
155format_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
536static void
537format_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
546static int
547format_get_number_of_directives (void *descr)
548{
549  struct spec *spec = (struct spec *) descr;
550
551  return spec->directives;
552}
553
554static bool
555format_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
643struct 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
661static void
662format_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
764int
765main ()
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