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