Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gettext-tools / src / format-c.c
1 /* C format strings.
2    Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc.
3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
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 /* C format strings are described in POSIX (IEEE P1003.1 2001), section
35    XSH 3 fprintf().  See also Linux fprintf(3) manual page.
36    A directive
37    - starts with '%' or '%m$' where m is a positive integer,
38    - is optionally followed by any of the characters '#', '0', '-', ' ', '+',
39      "'", or - only in msgstr strings - the string "I", each of which acts as
40      a flag,
41    - is optionally followed by a width specification: '*' (reads an argument)
42      or '*m$' or a nonempty digit sequence,
43    - is optionally followed by '.' and a precision specification: '*' (reads
44      an argument) or '*m$' or a nonempty digit sequence,
45    - is either continued like this:
46        - is optionally followed by a size specifier, one of 'hh' 'h' 'l' 'll'
47          'L' 'q' 'j' 'z' 't',
48        - is finished by a specifier
49            - '%', that needs no argument,
50            - 'c', 'C', that need a character argument,
51            - 's', 'S', that need a string argument,
52            - 'i', 'd', that need a signed integer argument,
53            - 'o', 'u', 'x', 'X', that need an unsigned integer argument,
54            - 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A', that need a floating-point
55              argument,
56            - 'p', that needs a 'void *' argument,
57            - 'n', that needs a pointer to integer.
58      or is finished by a specifier '<' inttypes-macro '>' where inttypes-macro
59      is an ISO C 99 section 7.8.1 format directive.
60    Numbered ('%m$' or '*m$') and unnumbered argument specifications cannot
61    be used in the same string.  When numbered argument specifications are
62    used, specifying the Nth argument requires that all the leading arguments,
63    from the first to the (N-1)th, are specified in the format string.
64  */
65
66 enum format_arg_type
67 {
68   FAT_NONE              = 0,
69   /* Basic types */
70   FAT_INTEGER           = 1,
71   FAT_DOUBLE            = 2,
72   FAT_CHAR              = 3,
73   FAT_STRING            = 4,
74   FAT_OBJC_OBJECT       = 5,
75   FAT_POINTER           = 6,
76   FAT_COUNT_POINTER     = 7,
77   /* Flags */
78   FAT_UNSIGNED          = 1 << 3,
79   FAT_SIZE_SHORT        = 1 << 4,
80   FAT_SIZE_CHAR         = 2 << 4,
81   FAT_SIZE_LONG         = 1 << 6,
82   FAT_SIZE_LONGLONG     = 2 << 6,
83   FAT_SIZE_8_T          = 1 << 8,
84   FAT_SIZE_16_T         = 1 << 9,
85   FAT_SIZE_32_T         = 1 << 10,
86   FAT_SIZE_64_T         = 1 << 11,
87   FAT_SIZE_LEAST8_T     = 1 << 12,
88   FAT_SIZE_LEAST16_T    = 1 << 13,
89   FAT_SIZE_LEAST32_T    = 1 << 14,
90   FAT_SIZE_LEAST64_T    = 1 << 15,
91   FAT_SIZE_FAST8_T      = 1 << 16,
92   FAT_SIZE_FAST16_T     = 1 << 17,
93   FAT_SIZE_FAST32_T     = 1 << 18,
94   FAT_SIZE_FAST64_T     = 1 << 19,
95   FAT_SIZE_INTMAX_T     = 1 << 20,
96   FAT_SIZE_INTPTR_T     = 1 << 21,
97   FAT_SIZE_SIZE_T       = 1 << 22,
98   FAT_SIZE_PTRDIFF_T    = 1 << 23,
99   FAT_WIDE              = FAT_SIZE_LONG,
100   /* Meaningful combinations of basic types and flags:
101   'signed char'                 = FAT_INTEGER | FAT_SIZE_CHAR,
102   'unsigned char'               = FAT_INTEGER | FAT_SIZE_CHAR | FAT_UNSIGNED,
103   'short'                       = FAT_INTEGER | FAT_SIZE_SHORT,
104   'unsigned short'              = FAT_INTEGER | FAT_SIZE_SHORT | FAT_UNSIGNED,
105   'int'                         = FAT_INTEGER,
106   'unsigned int'                = FAT_INTEGER | FAT_UNSIGNED,
107   'long int'                    = FAT_INTEGER | FAT_SIZE_LONG,
108   'unsigned long int'           = FAT_INTEGER | FAT_SIZE_LONG | FAT_UNSIGNED,
109   'long long int'               = FAT_INTEGER | FAT_SIZE_LONGLONG,
110   'unsigned long long int'      = FAT_INTEGER | FAT_SIZE_LONGLONG | FAT_UNSIGNED,
111   'double'                      = FAT_DOUBLE,
112   'long double'                 = FAT_DOUBLE | FAT_SIZE_LONGLONG,
113   'char'/'int'                  = FAT_CHAR,
114   'wchar_t'/'wint_t'            = FAT_CHAR | FAT_SIZE_LONG,
115   'const char *'                = FAT_STRING,
116   'const wchar_t *'             = FAT_STRING | FAT_SIZE_LONG,
117   'void *'                      = FAT_POINTER,
118   FAT_COUNT_SCHAR_POINTER       = FAT_COUNT_POINTER | FAT_SIZE_CHAR,
119   FAT_COUNT_SHORT_POINTER       = FAT_COUNT_POINTER | FAT_SIZE_SHORT,
120   FAT_COUNT_INT_POINTER         = FAT_COUNT_POINTER,
121   FAT_COUNT_LONGINT_POINTER     = FAT_COUNT_POINTER | FAT_SIZE_LONG,
122   FAT_COUNT_LONGLONGINT_POINTER = FAT_COUNT_POINTER | FAT_SIZE_LONGLONG,
123   */
124   /* Bitmasks */
125   FAT_SIZE_MASK         = (FAT_SIZE_SHORT | FAT_SIZE_CHAR
126                            | FAT_SIZE_LONG | FAT_SIZE_LONGLONG
127                            | FAT_SIZE_8_T | FAT_SIZE_16_T
128                            | FAT_SIZE_32_T | FAT_SIZE_64_T
129                            | FAT_SIZE_LEAST8_T | FAT_SIZE_LEAST16_T
130                            | FAT_SIZE_LEAST32_T | FAT_SIZE_LEAST64_T
131                            | FAT_SIZE_FAST8_T | FAT_SIZE_FAST16_T
132                            | FAT_SIZE_FAST32_T | FAT_SIZE_FAST64_T
133                            | FAT_SIZE_INTMAX_T | FAT_SIZE_INTPTR_T
134                            | FAT_SIZE_SIZE_T | FAT_SIZE_PTRDIFF_T)
135 };
136 #ifdef __cplusplus
137 typedef int format_arg_type_t;
138 #else
139 typedef enum format_arg_type format_arg_type_t;
140 #endif
141
142 struct numbered_arg
143 {
144   unsigned int number;
145   format_arg_type_t type;
146 };
147
148 struct unnumbered_arg
149 {
150   format_arg_type_t type;
151 };
152
153 struct spec
154 {
155   unsigned int directives;
156   unsigned int unnumbered_arg_count;
157   unsigned int allocated;
158   struct unnumbered_arg *unnumbered;
159   bool unlikely_intentional;
160   unsigned int sysdep_directives_count;
161   const char **sysdep_directives;
162 };
163
164 /* Locale independent test for a decimal digit.
165    Argument can be  'char' or 'unsigned char'.  (Whereas the argument of
166    <ctype.h> isdigit must be an 'unsigned char'.)  */
167 #undef isdigit
168 #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
169
170
171 static int
172 numbered_arg_compare (const void *p1, const void *p2)
173 {
174   unsigned int n1 = ((const struct numbered_arg *) p1)->number;
175   unsigned int n2 = ((const struct numbered_arg *) p2)->number;
176
177   return (n1 > n2 ? 1 : n1 < n2 ? -1 : 0);
178 }
179
180 #define INVALID_C99_MACRO(directive_number) \
181   xasprintf (_("In the directive number %u, the token after '<' is not the name of a format specifier macro. The valid macro names are listed in ISO C 99 section 7.8.1."), directive_number)
182
183 static void *
184 format_parse (const char *format, bool translated, bool objc_extensions,
185               char *fdi, char **invalid_reason)
186 {
187   const char *const format_start = format;
188   struct spec spec;
189   unsigned int numbered_arg_count;
190   struct numbered_arg *numbered;
191   struct spec *result;
192
193   spec.directives = 0;
194   numbered_arg_count = 0;
195   spec.unnumbered_arg_count = 0;
196   spec.allocated = 0;
197   numbered = NULL;
198   spec.unnumbered = NULL;
199   spec.unlikely_intentional = false;
200   spec.sysdep_directives_count = 0;
201   spec.sysdep_directives = NULL;
202
203   for (; *format != '\0';)
204     if (*format++ == '%')
205       {
206         /* A directive.  */
207         unsigned int number = 0;
208         format_arg_type_t type;
209         format_arg_type_t size;
210
211         FDI_SET (format - 1, FMTDIR_START);
212         spec.directives++;
213
214         if (isdigit (*format))
215           {
216             const char *f = format;
217             unsigned int m = 0;
218
219             do
220               {
221                 m = 10 * m + (*f - '0');
222                 f++;
223               }
224             while (isdigit (*f));
225
226             if (*f == '$')
227               {
228                 if (m == 0)
229                   {
230                     *invalid_reason = INVALID_ARGNO_0 (spec.directives);
231                     FDI_SET (f, FMTDIR_ERROR);
232                     goto bad_format;
233                   }
234                 number = m;
235                 format = ++f;
236               }
237           }
238
239         /* Parse flags.  */
240         for (;;)
241           {
242             if (*format == ' ' || *format == '+' || *format == '-'
243                 || *format == '#' || *format == '0' || *format == '\'')
244               format++;
245             else if (translated && *format == 'I')
246               {
247                 spec.sysdep_directives =
248                   (const char **)
249                   xrealloc (spec.sysdep_directives,
250                             2 * (spec.sysdep_directives_count + 1)
251                             * sizeof (const char *));
252                 spec.sysdep_directives[2 * spec.sysdep_directives_count] = format;
253                 spec.sysdep_directives[2 * spec.sysdep_directives_count + 1] = format + 1;
254                 spec.sysdep_directives_count++;
255                 format++;
256               }
257             else
258               break;
259           }
260
261         /* Parse width.  */
262         if (*format == '*')
263           {
264             unsigned int width_number = 0;
265
266             format++;
267
268             if (isdigit (*format))
269               {
270                 const char *f = format;
271                 unsigned int m = 0;
272
273                 do
274                   {
275                     m = 10 * m + (*f - '0');
276                     f++;
277                   }
278                 while (isdigit (*f));
279
280                 if (*f == '$')
281                   {
282                     if (m == 0)
283                       {
284                         *invalid_reason =
285                           INVALID_WIDTH_ARGNO_0 (spec.directives);
286                         FDI_SET (f, FMTDIR_ERROR);
287                         goto bad_format;
288                       }
289                     width_number = m;
290                     format = ++f;
291                   }
292               }
293
294             if (width_number)
295               {
296                 /* Numbered argument.  */
297
298                 /* Numbered and unnumbered specifications are exclusive.  */
299                 if (spec.unnumbered_arg_count > 0)
300                   {
301                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
302                     FDI_SET (format - 1, FMTDIR_ERROR);
303                     goto bad_format;
304                   }
305
306                 if (spec.allocated == numbered_arg_count)
307                   {
308                     spec.allocated = 2 * spec.allocated + 1;
309                     numbered = (struct numbered_arg *) xrealloc (numbered, spec.allocated * sizeof (struct numbered_arg));
310                   }
311                 numbered[numbered_arg_count].number = width_number;
312                 numbered[numbered_arg_count].type = FAT_INTEGER;
313                 numbered_arg_count++;
314               }
315             else
316               {
317                 /* Unnumbered argument.  */
318
319                 /* Numbered and unnumbered specifications are exclusive.  */
320                 if (numbered_arg_count > 0)
321                   {
322                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
323                     FDI_SET (format - 1, FMTDIR_ERROR);
324                     goto bad_format;
325                   }
326
327                 if (spec.allocated == spec.unnumbered_arg_count)
328                   {
329                     spec.allocated = 2 * spec.allocated + 1;
330                     spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
331                   }
332                 spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
333                 spec.unnumbered_arg_count++;
334               }
335           }
336         else if (isdigit (*format))
337           {
338             do format++; while (isdigit (*format));
339           }
340
341         /* Parse precision.  */
342         if (*format == '.')
343           {
344             format++;
345
346             if (*format == '*')
347               {
348                 unsigned int precision_number = 0;
349
350                 format++;
351
352                 if (isdigit (*format))
353                   {
354                     const char *f = format;
355                     unsigned int m = 0;
356
357                     do
358                       {
359                         m = 10 * m + (*f - '0');
360                         f++;
361                       }
362                     while (isdigit (*f));
363
364                     if (*f == '$')
365                       {
366                         if (m == 0)
367                           {
368                             *invalid_reason =
369                               INVALID_PRECISION_ARGNO_0 (spec.directives);
370                             FDI_SET (f, FMTDIR_ERROR);
371                             goto bad_format;
372                           }
373                         precision_number = m;
374                         format = ++f;
375                       }
376                   }
377
378                 if (precision_number)
379                   {
380                     /* Numbered argument.  */
381
382                     /* Numbered and unnumbered specifications are exclusive.  */
383                     if (spec.unnumbered_arg_count > 0)
384                       {
385                         *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
386                         FDI_SET (format - 1, FMTDIR_ERROR);
387                         goto bad_format;
388                       }
389
390                     if (spec.allocated == numbered_arg_count)
391                       {
392                         spec.allocated = 2 * spec.allocated + 1;
393                         numbered = (struct numbered_arg *) xrealloc (numbered, spec.allocated * sizeof (struct numbered_arg));
394                       }
395                     numbered[numbered_arg_count].number = precision_number;
396                     numbered[numbered_arg_count].type = FAT_INTEGER;
397                     numbered_arg_count++;
398                   }
399                 else
400                   {
401                     /* Unnumbered argument.  */
402
403                     /* Numbered and unnumbered specifications are exclusive.  */
404                     if (numbered_arg_count > 0)
405                       {
406                         *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
407                         FDI_SET (format - 1, FMTDIR_ERROR);
408                         goto bad_format;
409                       }
410
411                     if (spec.allocated == spec.unnumbered_arg_count)
412                       {
413                         spec.allocated = 2 * spec.allocated + 1;
414                         spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
415                       }
416                     spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
417                     spec.unnumbered_arg_count++;
418                   }
419               }
420             else if (isdigit (*format))
421               {
422                 do format++; while (isdigit (*format));
423               }
424           }
425
426         if (*format == '<')
427           {
428             spec.sysdep_directives =
429               (const char **)
430               xrealloc (spec.sysdep_directives,
431                         2 * (spec.sysdep_directives_count + 1)
432                         * sizeof (const char *));
433             spec.sysdep_directives[2 * spec.sysdep_directives_count] = format;
434
435             format++;
436             /* Parse ISO C 99 section 7.8.1 format string directive.
437                Syntax:
438                P R I { d | i | o | u | x | X }
439                { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR }  */
440             if (*format != 'P')
441               {
442                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
443                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
444                 goto bad_format;
445               }
446             format++;
447             if (*format != 'R')
448               {
449                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
450                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
451                 goto bad_format;
452               }
453             format++;
454             if (*format != 'I')
455               {
456                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
457                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
458                 goto bad_format;
459               }
460             format++;
461
462             switch (*format)
463               {
464               case 'i': case 'd':
465                 type = FAT_INTEGER;
466                 break;
467               case 'u': case 'o': case 'x': case 'X':
468                 type = FAT_INTEGER | FAT_UNSIGNED;
469                 break;
470               default:
471                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
472                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
473                 goto bad_format;
474               }
475             format++;
476
477             if (format[0] == 'M' && format[1] == 'A' && format[2] == 'X')
478               {
479                 type |= FAT_SIZE_INTMAX_T;
480                 format += 3;
481               }
482             else if (format[0] == 'P' && format[1] == 'T' && format[2] == 'R')
483               {
484                 type |= FAT_SIZE_INTPTR_T;
485                 format += 3;
486               }
487             else
488               {
489                 if (format[0] == 'L' && format[1] == 'E' && format[2] == 'A'
490                     && format[3] == 'S' && format[4] == 'T')
491                   {
492                     format += 5;
493                     if (format[0] == '8')
494                       {
495                         type |= FAT_SIZE_LEAST8_T;
496                         format++;
497                       }
498                     else if (format[0] == '1' && format[1] == '6')
499                       {
500                         type |= FAT_SIZE_LEAST16_T;
501                         format += 2;
502                       }
503                     else if (format[0] == '3' && format[1] == '2')
504                       {
505                         type |= FAT_SIZE_LEAST32_T;
506                         format += 2;
507                       }
508                     else if (format[0] == '6' && format[1] == '4')
509                       {
510                         type |= FAT_SIZE_LEAST64_T;
511                         format += 2;
512                       }
513                     else
514                       {
515                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
516                         FDI_SET (*format == '\0' ? format - 1 : format,
517                                  FMTDIR_ERROR);
518                         goto bad_format;
519                       }
520                   }
521                 else if (format[0] == 'F' && format[1] == 'A'
522                          && format[2] == 'S' && format[3] == 'T')
523                   {
524                     format += 4;
525                     if (format[0] == '8')
526                       {
527                         type |= FAT_SIZE_FAST8_T;
528                         format++;
529                       }
530                     else if (format[0] == '1' && format[1] == '6')
531                       {
532                         type |= FAT_SIZE_FAST16_T;
533                         format += 2;
534                       }
535                     else if (format[0] == '3' && format[1] == '2')
536                       {
537                         type |= FAT_SIZE_FAST32_T;
538                         format += 2;
539                       }
540                     else if (format[0] == '6' && format[1] == '4')
541                       {
542                         type |= FAT_SIZE_FAST64_T;
543                         format += 2;
544                       }
545                     else
546                       {
547                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
548                         FDI_SET (*format == '\0' ? format - 1 : format,
549                                  FMTDIR_ERROR);
550                         goto bad_format;
551                       }
552                   }
553                 else
554                   {
555                     if (format[0] == '8')
556                       {
557                         type |= FAT_SIZE_8_T;
558                         format++;
559                       }
560                     else if (format[0] == '1' && format[1] == '6')
561                       {
562                         type |= FAT_SIZE_16_T;
563                         format += 2;
564                       }
565                     else if (format[0] == '3' && format[1] == '2')
566                       {
567                         type |= FAT_SIZE_32_T;
568                         format += 2;
569                       }
570                     else if (format[0] == '6' && format[1] == '4')
571                       {
572                         type |= FAT_SIZE_64_T;
573                         format += 2;
574                       }
575                     else
576                       {
577                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
578                         FDI_SET (*format == '\0' ? format - 1 : format,
579                                  FMTDIR_ERROR);
580                         goto bad_format;
581                       }
582                   }
583               }
584
585             if (*format != '>')
586               {
587                 *invalid_reason =
588                   xasprintf (_("In the directive number %u, the token after '<' is not followed by '>'."), spec.directives);
589                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
590                 goto bad_format;
591               }
592
593             spec.sysdep_directives[2 * spec.sysdep_directives_count + 1] = format + 1;
594             spec.sysdep_directives_count++;
595           }
596         else
597           {
598             /* Parse size.  */
599             size = 0;
600             for (;; format++)
601               {
602                 if (*format == 'h')
603                   {
604                     if (size & (FAT_SIZE_SHORT | FAT_SIZE_CHAR))
605                       size = FAT_SIZE_CHAR;
606                     else
607                       size = FAT_SIZE_SHORT;
608                   }
609                 else if (*format == 'l')
610                   {
611                     if (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG))
612                       size = FAT_SIZE_LONGLONG;
613                     else
614                       size = FAT_SIZE_LONG;
615                   }
616                 else if (*format == 'L')
617                   size = FAT_SIZE_LONGLONG;
618                 else if (*format == 'q')
619                   /* Old BSD 4.4 convention.  */
620                   size = FAT_SIZE_LONGLONG;
621                 else if (*format == 'j')
622                   size = FAT_SIZE_INTMAX_T;
623                 else if (*format == 'z' || *format == 'Z')
624                   /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
625                      because the warning facility in gcc-2.95.2 understands
626                      only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
627                   size = FAT_SIZE_SIZE_T;
628                 else if (*format == 't')
629                   size = FAT_SIZE_PTRDIFF_T;
630                 else
631                   break;
632               }
633
634             switch (*format)
635               {
636               case '%':
637                 /* Programmers writing _("%2%") most often will not want to
638                    use this string as a c-format string, but rather as a
639                    literal or as a different kind of format string.  */
640                 if (format[-1] != '%')
641                   spec.unlikely_intentional = true;
642                 type = FAT_NONE;
643                 break;
644               case 'm': /* glibc extension */
645                 type = FAT_NONE;
646                 break;
647               case 'c':
648                 type = FAT_CHAR;
649                 type |= (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG)
650                          ? FAT_WIDE : 0);
651                 break;
652               case 'C': /* obsolete */
653                 type = FAT_CHAR | FAT_WIDE;
654                 break;
655               case 's':
656                 type = FAT_STRING;
657                 type |= (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG)
658                          ? FAT_WIDE : 0);
659                 break;
660               case 'S': /* obsolete */
661                 type = FAT_STRING | FAT_WIDE;
662                 break;
663               case 'i': case 'd':
664                 type = FAT_INTEGER;
665                 type |= (size & FAT_SIZE_MASK);
666                 break;
667               case 'u': case 'o': case 'x': case 'X':
668                 type = FAT_INTEGER | FAT_UNSIGNED;
669                 type |= (size & FAT_SIZE_MASK);
670                 break;
671               case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
672               case 'a': case 'A':
673                 type = FAT_DOUBLE;
674                 type |= (size & FAT_SIZE_LONGLONG);
675                 break;
676               case '@':
677                 if (objc_extensions)
678                   {
679                     type = FAT_OBJC_OBJECT;
680                     break;
681                   }
682                 goto other;
683               case 'p':
684                 type = FAT_POINTER;
685                 break;
686               case 'n':
687                 type = FAT_COUNT_POINTER;
688                 type |= (size & FAT_SIZE_MASK);
689                 break;
690               other:
691               default:
692                 if (*format == '\0')
693                   {
694                     *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
695                     FDI_SET (format - 1, FMTDIR_ERROR);
696                   }
697                 else
698                   {
699                     *invalid_reason =
700                       INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
701                     FDI_SET (format, FMTDIR_ERROR);
702                   }
703                 goto bad_format;
704               }
705           }
706
707         if (type != FAT_NONE)
708           {
709             if (number)
710               {
711                 /* Numbered argument.  */
712
713                 /* Numbered and unnumbered specifications are exclusive.  */
714                 if (spec.unnumbered_arg_count > 0)
715                   {
716                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
717                     FDI_SET (format, FMTDIR_ERROR);
718                     goto bad_format;
719                   }
720
721                 if (spec.allocated == numbered_arg_count)
722                   {
723                     spec.allocated = 2 * spec.allocated + 1;
724                     numbered = (struct numbered_arg *) xrealloc (numbered, spec.allocated * sizeof (struct numbered_arg));
725                   }
726                 numbered[numbered_arg_count].number = number;
727                 numbered[numbered_arg_count].type = type;
728                 numbered_arg_count++;
729               }
730             else
731               {
732                 /* Unnumbered argument.  */
733
734                 /* Numbered and unnumbered specifications are exclusive.  */
735                 if (numbered_arg_count > 0)
736                   {
737                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
738                     FDI_SET (format, FMTDIR_ERROR);
739                     goto bad_format;
740                   }
741
742                 if (spec.allocated == spec.unnumbered_arg_count)
743                   {
744                     spec.allocated = 2 * spec.allocated + 1;
745                     spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
746                   }
747                 spec.unnumbered[spec.unnumbered_arg_count].type = type;
748                 spec.unnumbered_arg_count++;
749               }
750           }
751
752         FDI_SET (format, FMTDIR_END);
753
754         format++;
755       }
756
757   /* Sort the numbered argument array, and eliminate duplicates.  */
758   if (numbered_arg_count > 1)
759     {
760       unsigned int i, j;
761       bool err;
762
763       qsort (numbered, numbered_arg_count,
764              sizeof (struct numbered_arg), numbered_arg_compare);
765
766       /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
767       err = false;
768       for (i = j = 0; i < numbered_arg_count; i++)
769         if (j > 0 && numbered[i].number == numbered[j-1].number)
770           {
771             format_arg_type_t type1 = numbered[i].type;
772             format_arg_type_t type2 = numbered[j-1].type;
773             format_arg_type_t type_both;
774
775             if (type1 == type2)
776               type_both = type1;
777             else
778               {
779                 /* Incompatible types.  */
780                 type_both = FAT_NONE;
781                 if (!err)
782                   *invalid_reason =
783                     INVALID_INCOMPATIBLE_ARG_TYPES (numbered[i].number);
784                 err = true;
785               }
786
787             numbered[j-1].type = type_both;
788           }
789         else
790           {
791             if (j < i)
792               {
793                 numbered[j].number = numbered[i].number;
794                 numbered[j].type = numbered[i].type;
795               }
796             j++;
797           }
798       numbered_arg_count = j;
799       if (err)
800         /* *invalid_reason has already been set above.  */
801         goto bad_format;
802     }
803
804   /* Verify that the format strings uses all arguments up to the highest
805      numbered one.  */
806   if (numbered_arg_count > 0)
807     {
808       unsigned int i;
809
810       for (i = 0; i < numbered_arg_count; i++)
811         if (numbered[i].number != i + 1)
812           {
813             *invalid_reason =
814               xasprintf (_("The string refers to argument number %u but ignores argument number %u."), numbered[i].number, i + 1);
815             goto bad_format;
816           }
817
818       /* So now the numbered arguments array is equivalent to a sequence
819          of unnumbered arguments.  */
820       spec.unnumbered_arg_count = numbered_arg_count;
821       spec.allocated = spec.unnumbered_arg_count;
822       spec.unnumbered = XNMALLOC (spec.allocated, struct unnumbered_arg);
823       for (i = 0; i < spec.unnumbered_arg_count; i++)
824         spec.unnumbered[i].type = numbered[i].type;
825       free (numbered);
826       numbered_arg_count = 0;
827     }
828
829   result = XMALLOC (struct spec);
830   *result = spec;
831   return result;
832
833  bad_format:
834   if (numbered != NULL)
835     free (numbered);
836   if (spec.unnumbered != NULL)
837     free (spec.unnumbered);
838   if (spec.sysdep_directives != NULL)
839     free (spec.sysdep_directives);
840   return NULL;
841 }
842
843 static void *
844 format_c_parse (const char *format, bool translated, char *fdi,
845                 char **invalid_reason)
846 {
847   return format_parse (format, translated, false, fdi, invalid_reason);
848 }
849
850 static void *
851 format_objc_parse (const char *format, bool translated, char *fdi,
852                    char **invalid_reason)
853 {
854   return format_parse (format, translated, true, fdi, invalid_reason);
855 }
856
857 static void
858 format_free (void *descr)
859 {
860   struct spec *spec = (struct spec *) descr;
861
862   if (spec->unnumbered != NULL)
863     free (spec->unnumbered);
864   if (spec->sysdep_directives != NULL)
865     free (spec->sysdep_directives);
866   free (spec);
867 }
868
869 static bool
870 format_is_unlikely_intentional (void *descr)
871 {
872   struct spec *spec = (struct spec *) descr;
873
874   return spec->unlikely_intentional;
875 }
876
877 static int
878 format_get_number_of_directives (void *descr)
879 {
880   struct spec *spec = (struct spec *) descr;
881
882   return spec->directives;
883 }
884
885 static bool
886 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
887               formatstring_error_logger_t error_logger,
888               const char *pretty_msgid, const char *pretty_msgstr)
889 {
890   struct spec *spec1 = (struct spec *) msgid_descr;
891   struct spec *spec2 = (struct spec *) msgstr_descr;
892   bool err = false;
893   unsigned int i;
894
895   /* Check the argument types are the same.  */
896   if (equality
897       ? spec1->unnumbered_arg_count != spec2->unnumbered_arg_count
898       : spec1->unnumbered_arg_count < spec2->unnumbered_arg_count)
899     {
900       if (error_logger)
901         error_logger (_("number of format specifications in '%s' and '%s' does not match"),
902                       pretty_msgid, pretty_msgstr);
903       err = true;
904     }
905   else
906     for (i = 0; i < spec2->unnumbered_arg_count; i++)
907       if (spec1->unnumbered[i].type != spec2->unnumbered[i].type)
908         {
909           if (error_logger)
910             error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
911                           pretty_msgid, pretty_msgstr, i + 1);
912           err = true;
913         }
914
915   return err;
916 }
917
918
919 struct formatstring_parser formatstring_c =
920 {
921   format_c_parse,
922   format_free,
923   format_get_number_of_directives,
924   format_is_unlikely_intentional,
925   format_check
926 };
927
928
929 struct formatstring_parser formatstring_objc =
930 {
931   format_objc_parse,
932   format_free,
933   format_get_number_of_directives,
934   format_is_unlikely_intentional,
935   format_check
936 };
937
938
939 void
940 get_sysdep_c_format_directives (const char *string, bool translated,
941                                 struct interval **intervalsp, size_t *lengthp)
942 {
943   /* Parse the format string with all possible extensions turned on.  (The
944      caller has already verified that the format string is valid for the
945      particular language.)  */
946   char *invalid_reason = NULL;
947   struct spec *descr =
948     (struct spec *)
949     format_parse (string, translated, true, NULL, &invalid_reason);
950
951   if (descr != NULL && descr->sysdep_directives_count > 0)
952     {
953       unsigned int n = descr->sysdep_directives_count;
954       struct interval *intervals = XNMALLOC (n, struct interval);
955       unsigned int i;
956
957       for (i = 0; i < n; i++)
958         {
959           intervals[i].startpos = descr->sysdep_directives[2 * i] - string;
960           intervals[i].endpos = descr->sysdep_directives[2 * i + 1] - string;
961         }
962       *intervalsp = intervals;
963       *lengthp = n;
964     }
965   else
966     {
967       *intervalsp = NULL;
968       *lengthp = 0;
969     }
970
971   if (descr != NULL)
972     format_free (descr);
973   else
974     free (invalid_reason);
975 }
976
977
978 #ifdef TEST
979
980 /* Test program: Print the argument list specification returned by
981    format_parse for strings read from standard input.  */
982
983 #include <stdio.h>
984
985 static void
986 format_print (void *descr)
987 {
988   struct spec *spec = (struct spec *) descr;
989   unsigned int i;
990
991   if (spec == NULL)
992     {
993       printf ("INVALID");
994       return;
995     }
996
997   printf ("(");
998   for (i = 0; i < spec->unnumbered_arg_count; i++)
999     {
1000       if (i > 0)
1001         printf (" ");
1002       if (spec->unnumbered[i].type & FAT_UNSIGNED)
1003         printf ("[unsigned]");
1004       switch (spec->unnumbered[i].type & FAT_SIZE_MASK)
1005         {
1006         case 0:
1007           break;
1008         case FAT_SIZE_SHORT:
1009           printf ("[short]");
1010           break;
1011         case FAT_SIZE_CHAR:
1012           printf ("[char]");
1013           break;
1014         case FAT_SIZE_LONG:
1015           printf ("[long]");
1016           break;
1017         case FAT_SIZE_LONGLONG:
1018           printf ("[long long]");
1019           break;
1020         case FAT_SIZE_8_T:
1021           printf ("[int8_t]");
1022           break;
1023         case FAT_SIZE_16_T:
1024           printf ("[int16_t]");
1025           break;
1026         case FAT_SIZE_32_T:
1027           printf ("[int32_t]");
1028           break;
1029         case FAT_SIZE_64_T:
1030           printf ("[int64_t]");
1031           break;
1032         case FAT_SIZE_LEAST8_T:
1033           printf ("[int_least8_t]");
1034           break;
1035         case FAT_SIZE_LEAST16_T:
1036           printf ("[int_least16_t]");
1037           break;
1038         case FAT_SIZE_LEAST32_T:
1039           printf ("[int_least32_t]");
1040           break;
1041         case FAT_SIZE_LEAST64_T:
1042           printf ("[int_least64_t]");
1043           break;
1044         case FAT_SIZE_FAST8_T:
1045           printf ("[int_fast8_t]");
1046           break;
1047         case FAT_SIZE_FAST16_T:
1048           printf ("[int_fast16_t]");
1049           break;
1050         case FAT_SIZE_FAST32_T:
1051           printf ("[int_fast32_t]");
1052           break;
1053         case FAT_SIZE_FAST64_T:
1054           printf ("[int_fast64_t]");
1055           break;
1056         case FAT_SIZE_INTMAX_T:
1057           printf ("[intmax_t]");
1058           break;
1059         case FAT_SIZE_INTPTR_T:
1060           printf ("[intptr_t]");
1061           break;
1062         case FAT_SIZE_SIZE_T:
1063           printf ("[size_t]");
1064           break;
1065         case FAT_SIZE_PTRDIFF_T:
1066           printf ("[ptrdiff_t]");
1067           break;
1068         default:
1069           abort ();
1070         }
1071       switch (spec->unnumbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_MASK))
1072         {
1073         case FAT_INTEGER:
1074           printf ("i");
1075           break;
1076         case FAT_DOUBLE:
1077           printf ("f");
1078           break;
1079         case FAT_CHAR:
1080           printf ("c");
1081           break;
1082         case FAT_STRING:
1083           printf ("s");
1084           break;
1085         case FAT_OBJC_OBJECT:
1086           printf ("@");
1087           break;
1088         case FAT_POINTER:
1089           printf ("p");
1090           break;
1091         case FAT_COUNT_POINTER:
1092           printf ("n");
1093           break;
1094         default:
1095           abort ();
1096         }
1097     }
1098   printf (")");
1099 }
1100
1101 int
1102 main ()
1103 {
1104   for (;;)
1105     {
1106       char *line = NULL;
1107       size_t line_size = 0;
1108       int line_len;
1109       char *invalid_reason;
1110       void *descr;
1111
1112       line_len = getline (&line, &line_size, stdin);
1113       if (line_len < 0)
1114         break;
1115       if (line_len > 0 && line[line_len - 1] == '\n')
1116         line[--line_len] = '\0';
1117
1118       invalid_reason = NULL;
1119       descr = format_c_parse (line, false, NULL, &invalid_reason);
1120
1121       format_print (descr);
1122       printf ("\n");
1123       if (descr == NULL)
1124         printf ("%s\n", invalid_reason);
1125
1126       free (invalid_reason);
1127       free (line);
1128     }
1129
1130   return 0;
1131 }
1132
1133 /*
1134  * For Emacs M-x compile
1135  * Local Variables:
1136  * 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-c.c ../gnulib-lib/libgettextlib.la"
1137  * End:
1138  */
1139
1140 #endif /* TEST */