• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Parsing C format strings.
2    Copyright (C) 2001-2004, 2006-2007, 2009-2010, 2018, 2020 Free Software
3    Foundation, Inc.
4    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
18 
19 
20 /* C format strings are described in POSIX (IEEE P1003.1 2001), section
21    XSH 3 fprintf().  See also Linux fprintf(3) manual page.
22    A directive
23    - starts with '%' or '%m$' where m is a positive integer,
24    - is optionally followed by any of the characters '#', '0', '-', ' ', '+',
25      "'", or - only in msgstr strings - the string "I", each of which acts as
26      a flag,
27    - is optionally followed by a width specification: '*' (reads an argument)
28      or '*m$' or a nonempty digit sequence,
29    - is optionally followed by '.' and a precision specification: '*' (reads
30      an argument) or '*m$' or a nonempty digit sequence,
31    - is either continued like this:
32        - is optionally followed by a size specifier, one of 'hh' 'h' 'l' 'll'
33          'L' 'q' 'j' 'z' 't',
34        - is finished by a specifier
35            - '%', that needs no argument,
36            - 'c', 'C', that need a character argument,
37            - 's', 'S', that need a string argument,
38            - 'i', 'd', that need a signed integer argument,
39            - 'o', 'u', 'x', 'X', that need an unsigned integer argument,
40            - 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A', that need a floating-point
41              argument,
42            - 'p', that needs a 'void *' argument,
43            - 'n', that needs a pointer to integer.
44      or is finished by a specifier '<' inttypes-macro '>' where inttypes-macro
45      is an ISO C 99 section 7.8.1 format directive.
46    Numbered ('%m$' or '*m$') and unnumbered argument specifications cannot
47    be used in the same string.  When numbered argument specifications are
48    used, specifying the Nth argument requires that all the leading arguments,
49    from the first to the (N-1)th, are specified in the format string.
50  */
51 
52 enum format_arg_type
53 {
54   FAT_NONE              = 0,
55   /* Basic types */
56   FAT_INTEGER           = 1,
57   FAT_DOUBLE            = 2,
58   FAT_CHAR              = 3,
59   FAT_STRING            = 4,
60   FAT_OBJC_OBJECT       = 5,
61   FAT_POINTER           = 6,
62   FAT_COUNT_POINTER     = 7,
63   /* Flags */
64   FAT_UNSIGNED          = 1 << 3,
65   FAT_SIZE_SHORT        = 1 << 4,
66   FAT_SIZE_CHAR         = 2 << 4,
67   FAT_SIZE_LONG         = 1 << 6,
68   FAT_SIZE_LONGLONG     = 2 << 6,
69   FAT_SIZE_8_T          = 1 << 8,
70   FAT_SIZE_16_T         = 1 << 9,
71   FAT_SIZE_32_T         = 1 << 10,
72   FAT_SIZE_64_T         = 1 << 11,
73   FAT_SIZE_LEAST8_T     = 1 << 12,
74   FAT_SIZE_LEAST16_T    = 1 << 13,
75   FAT_SIZE_LEAST32_T    = 1 << 14,
76   FAT_SIZE_LEAST64_T    = 1 << 15,
77   FAT_SIZE_FAST8_T      = 1 << 16,
78   FAT_SIZE_FAST16_T     = 1 << 17,
79   FAT_SIZE_FAST32_T     = 1 << 18,
80   FAT_SIZE_FAST64_T     = 1 << 19,
81   FAT_SIZE_INTMAX_T     = 1 << 20,
82   FAT_SIZE_INTPTR_T     = 1 << 21,
83   FAT_SIZE_SIZE_T       = 1 << 22,
84   FAT_SIZE_PTRDIFF_T    = 1 << 23,
85   FAT_WIDE              = FAT_SIZE_LONG,
86   /* Meaningful combinations of basic types and flags:
87   'signed char'                 = FAT_INTEGER | FAT_SIZE_CHAR,
88   'unsigned char'               = FAT_INTEGER | FAT_SIZE_CHAR | FAT_UNSIGNED,
89   'short'                       = FAT_INTEGER | FAT_SIZE_SHORT,
90   'unsigned short'              = FAT_INTEGER | FAT_SIZE_SHORT | FAT_UNSIGNED,
91   'int'                         = FAT_INTEGER,
92   'unsigned int'                = FAT_INTEGER | FAT_UNSIGNED,
93   'long int'                    = FAT_INTEGER | FAT_SIZE_LONG,
94   'unsigned long int'           = FAT_INTEGER | FAT_SIZE_LONG | FAT_UNSIGNED,
95   'long long int'               = FAT_INTEGER | FAT_SIZE_LONGLONG,
96   'unsigned long long int'      = FAT_INTEGER | FAT_SIZE_LONGLONG | FAT_UNSIGNED,
97   'double'                      = FAT_DOUBLE,
98   'long double'                 = FAT_DOUBLE | FAT_SIZE_LONGLONG,
99   'char'/'int'                  = FAT_CHAR,
100   'wchar_t'/'wint_t'            = FAT_CHAR | FAT_SIZE_LONG,
101   'const char *'                = FAT_STRING,
102   'const wchar_t *'             = FAT_STRING | FAT_SIZE_LONG,
103   'void *'                      = FAT_POINTER,
104   FAT_COUNT_SCHAR_POINTER       = FAT_COUNT_POINTER | FAT_SIZE_CHAR,
105   FAT_COUNT_SHORT_POINTER       = FAT_COUNT_POINTER | FAT_SIZE_SHORT,
106   FAT_COUNT_INT_POINTER         = FAT_COUNT_POINTER,
107   FAT_COUNT_LONGINT_POINTER     = FAT_COUNT_POINTER | FAT_SIZE_LONG,
108   FAT_COUNT_LONGLONGINT_POINTER = FAT_COUNT_POINTER | FAT_SIZE_LONGLONG,
109   */
110   /* Bitmasks */
111   FAT_BASIC_MASK        = (FAT_INTEGER | FAT_DOUBLE | FAT_CHAR | FAT_STRING
112                            | FAT_OBJC_OBJECT | FAT_POINTER | FAT_COUNT_POINTER),
113   FAT_SIZE_MASK         = (FAT_SIZE_SHORT | FAT_SIZE_CHAR
114                            | FAT_SIZE_LONG | FAT_SIZE_LONGLONG
115                            | FAT_SIZE_8_T | FAT_SIZE_16_T
116                            | FAT_SIZE_32_T | FAT_SIZE_64_T
117                            | FAT_SIZE_LEAST8_T | FAT_SIZE_LEAST16_T
118                            | FAT_SIZE_LEAST32_T | FAT_SIZE_LEAST64_T
119                            | FAT_SIZE_FAST8_T | FAT_SIZE_FAST16_T
120                            | FAT_SIZE_FAST32_T | FAT_SIZE_FAST64_T
121                            | FAT_SIZE_INTMAX_T | FAT_SIZE_INTPTR_T
122                            | FAT_SIZE_SIZE_T | FAT_SIZE_PTRDIFF_T)
123 };
124 #ifdef __cplusplus
125 typedef int format_arg_type_t;
126 #else
127 typedef enum format_arg_type format_arg_type_t;
128 #endif
129 
130 struct numbered_arg
131 {
132   unsigned int number;
133   format_arg_type_t type;
134 };
135 
136 struct unnumbered_arg
137 {
138   format_arg_type_t type;
139 };
140 
141 struct spec
142 {
143   unsigned int directives;
144   unsigned int unnumbered_arg_count;
145   struct unnumbered_arg *unnumbered;
146   bool unlikely_intentional;
147   unsigned int sysdep_directives_count;
148   const char **sysdep_directives;
149 };
150 
151 /* Locale independent test for a decimal digit.
152    Argument can be  'char' or 'unsigned char'.  (Whereas the argument of
153    <ctype.h> isdigit must be an 'unsigned char'.)  */
154 #undef isdigit
155 #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
156 
157 /* Whether to recognize the 'I' flag.  */
158 #if SYSDEP_SEGMENTS_PROCESSED
159 /* The 'I' flag can only occur in glibc >= 2.2.  On other platforms, gettext()
160    filters it away even if it is present in the msgstr in the .mo file.  */
161 # define HANDLE_I_FLAG \
162    ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) \
163     && !defined __UCLIBC__)
164 #else
165 # define HANDLE_I_FLAG 1
166 #endif
167 
168 
169 static int
numbered_arg_compare(const void * p1,const void * p2)170 numbered_arg_compare (const void *p1, const void *p2)
171 {
172   unsigned int n1 = ((const struct numbered_arg *) p1)->number;
173   unsigned int n2 = ((const struct numbered_arg *) p2)->number;
174 
175   return (n1 > n2 ? 1 : n1 < n2 ? -1 : 0);
176 }
177 
178 static struct spec *
format_parse_entrails(const char * format,bool translated,bool objc_extensions,char * fdi,char ** invalid_reason,struct spec * result)179 format_parse_entrails (const char *format, bool translated,
180                        bool objc_extensions, char *fdi, char **invalid_reason,
181                        struct spec *result)
182 {
183   const char *const format_start = format;
184   struct spec spec;
185   unsigned int numbered_arg_count;
186   struct numbered_arg *numbered;
187   unsigned int allocated;
188 
189   spec.directives = 0;
190   spec.unnumbered_arg_count = 0;
191   spec.unnumbered = NULL;
192   spec.unlikely_intentional = false;
193   spec.sysdep_directives_count = 0;
194   spec.sysdep_directives = NULL;
195   numbered_arg_count = 0;
196   numbered = NULL;
197   allocated = 0;
198 
199   for (; *format != '\0';)
200     if (*format++ == '%')
201       {
202         /* A directive.  */
203         unsigned int number = 0;
204         format_arg_type_t type;
205         format_arg_type_t size;
206 
207         FDI_SET (format - 1, FMTDIR_START);
208         spec.directives++;
209 
210         if (isdigit (*format))
211           {
212             const char *f = format;
213             unsigned int m = 0;
214 
215             do
216               {
217                 m = 10 * m + (*f - '0');
218                 f++;
219               }
220             while (isdigit (*f));
221 
222             if (*f == '$')
223               {
224                 if (m == 0)
225                   {
226                     *invalid_reason = INVALID_ARGNO_0 (spec.directives);
227                     FDI_SET (f, FMTDIR_ERROR);
228                     goto bad_format;
229                   }
230                 number = m;
231                 format = ++f;
232               }
233           }
234 
235         /* Parse flags.  */
236         for (;;)
237           {
238             if (*format == ' ' || *format == '+' || *format == '-'
239                 || *format == '#' || *format == '0' || *format == '\'')
240               format++;
241 #if HANDLE_I_FLAG
242             else if (translated && *format == 'I')
243               {
244                 spec.sysdep_directives =
245                   (const char **)
246                   xrealloc (spec.sysdep_directives,
247                             2 * (spec.sysdep_directives_count + 1)
248                             * sizeof (const char *));
249                 IF_OOM (spec.sysdep_directives, goto bad_format;)
250                 spec.sysdep_directives[2 * spec.sysdep_directives_count] = format;
251                 spec.sysdep_directives[2 * spec.sysdep_directives_count + 1] = format + 1;
252                 spec.sysdep_directives_count++;
253                 format++;
254               }
255 #endif
256             else
257               break;
258           }
259 
260         /* Parse width.  */
261         if (*format == '*')
262           {
263             unsigned int width_number = 0;
264 
265             format++;
266 
267             if (isdigit (*format))
268               {
269                 const char *f = format;
270                 unsigned int m = 0;
271 
272                 do
273                   {
274                     m = 10 * m + (*f - '0');
275                     f++;
276                   }
277                 while (isdigit (*f));
278 
279                 if (*f == '$')
280                   {
281                     if (m == 0)
282                       {
283                         *invalid_reason =
284                           INVALID_WIDTH_ARGNO_0 (spec.directives);
285                         FDI_SET (f, FMTDIR_ERROR);
286                         goto bad_format;
287                       }
288                     width_number = m;
289                     format = ++f;
290                   }
291               }
292 
293             if (width_number)
294               {
295                 /* Numbered argument.  */
296 
297                 /* Numbered and unnumbered specifications are exclusive.  */
298                 if (spec.unnumbered_arg_count > 0)
299                   {
300                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
301                     FDI_SET (format - 1, FMTDIR_ERROR);
302                     goto bad_format;
303                   }
304 
305                 if (allocated == numbered_arg_count)
306                   {
307                     allocated = 2 * allocated + 1;
308                     numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg));
309                     IF_OOM (numbered, goto bad_format;)
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 (allocated == spec.unnumbered_arg_count)
328                   {
329                     allocated = 2 * allocated + 1;
330                     spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, allocated * sizeof (struct unnumbered_arg));
331                     IF_OOM (spec.unnumbered, goto bad_format;)
332                   }
333                 spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
334                 spec.unnumbered_arg_count++;
335               }
336           }
337         else if (isdigit (*format))
338           {
339             do format++; while (isdigit (*format));
340           }
341 
342         /* Parse precision.  */
343         if (*format == '.')
344           {
345             format++;
346 
347             if (*format == '*')
348               {
349                 unsigned int precision_number = 0;
350 
351                 format++;
352 
353                 if (isdigit (*format))
354                   {
355                     const char *f = format;
356                     unsigned int m = 0;
357 
358                     do
359                       {
360                         m = 10 * m + (*f - '0');
361                         f++;
362                       }
363                     while (isdigit (*f));
364 
365                     if (*f == '$')
366                       {
367                         if (m == 0)
368                           {
369                             *invalid_reason =
370                               INVALID_PRECISION_ARGNO_0 (spec.directives);
371                             FDI_SET (f, FMTDIR_ERROR);
372                             goto bad_format;
373                           }
374                         precision_number = m;
375                         format = ++f;
376                       }
377                   }
378 
379                 if (precision_number)
380                   {
381                     /* Numbered argument.  */
382 
383                     /* Numbered and unnumbered specifications are exclusive.  */
384                     if (spec.unnumbered_arg_count > 0)
385                       {
386                         *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
387                         FDI_SET (format - 1, FMTDIR_ERROR);
388                         goto bad_format;
389                       }
390 
391                     if (allocated == numbered_arg_count)
392                       {
393                         allocated = 2 * allocated + 1;
394                         numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg));
395                         IF_OOM (numbered, goto bad_format;)
396                       }
397                     numbered[numbered_arg_count].number = precision_number;
398                     numbered[numbered_arg_count].type = FAT_INTEGER;
399                     numbered_arg_count++;
400                   }
401                 else
402                   {
403                     /* Unnumbered argument.  */
404 
405                     /* Numbered and unnumbered specifications are exclusive.  */
406                     if (numbered_arg_count > 0)
407                       {
408                         *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
409                         FDI_SET (format - 1, FMTDIR_ERROR);
410                         goto bad_format;
411                       }
412 
413                     if (allocated == spec.unnumbered_arg_count)
414                       {
415                         allocated = 2 * allocated + 1;
416                         spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, allocated * sizeof (struct unnumbered_arg));
417                         IF_OOM (spec.unnumbered, goto bad_format;)
418                       }
419                     spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
420                     spec.unnumbered_arg_count++;
421                   }
422               }
423             else if (isdigit (*format))
424               {
425                 do format++; while (isdigit (*format));
426               }
427           }
428 
429         if (!SYSDEP_SEGMENTS_PROCESSED && *format == '<')
430           {
431             spec.sysdep_directives =
432               (const char **)
433               xrealloc (spec.sysdep_directives,
434                         2 * (spec.sysdep_directives_count + 1)
435                         * sizeof (const char *));
436             IF_OOM (spec.sysdep_directives, goto bad_format;)
437             spec.sysdep_directives[2 * spec.sysdep_directives_count] = format;
438 
439             format++;
440             /* Parse ISO C 99 section 7.8.1 format string directive.
441                Syntax:
442                P R I { d | i | o | u | x | X }
443                { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR }  */
444             if (*format != 'P')
445               {
446                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
447                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
448                 goto bad_format;
449               }
450             format++;
451             if (*format != 'R')
452               {
453                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
454                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
455                 goto bad_format;
456               }
457             format++;
458             if (*format != 'I')
459               {
460                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
461                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
462                 goto bad_format;
463               }
464             format++;
465 
466             switch (*format)
467               {
468               case 'i': case 'd':
469                 type = FAT_INTEGER;
470                 break;
471               case 'u': case 'o': case 'x': case 'X':
472                 type = FAT_INTEGER | FAT_UNSIGNED;
473                 break;
474               default:
475                 *invalid_reason = INVALID_C99_MACRO (spec.directives);
476                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
477                 goto bad_format;
478               }
479             format++;
480 
481             if (format[0] == 'M' && format[1] == 'A' && format[2] == 'X')
482               {
483                 type |= FAT_SIZE_INTMAX_T;
484                 format += 3;
485               }
486             else if (format[0] == 'P' && format[1] == 'T' && format[2] == 'R')
487               {
488                 type |= FAT_SIZE_INTPTR_T;
489                 format += 3;
490               }
491             else
492               {
493                 if (format[0] == 'L' && format[1] == 'E' && format[2] == 'A'
494                     && format[3] == 'S' && format[4] == 'T')
495                   {
496                     format += 5;
497                     if (format[0] == '8')
498                       {
499                         type |= FAT_SIZE_LEAST8_T;
500                         format++;
501                       }
502                     else if (format[0] == '1' && format[1] == '6')
503                       {
504                         type |= FAT_SIZE_LEAST16_T;
505                         format += 2;
506                       }
507                     else if (format[0] == '3' && format[1] == '2')
508                       {
509                         type |= FAT_SIZE_LEAST32_T;
510                         format += 2;
511                       }
512                     else if (format[0] == '6' && format[1] == '4')
513                       {
514                         type |= FAT_SIZE_LEAST64_T;
515                         format += 2;
516                       }
517                     else
518                       {
519                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
520                         FDI_SET (*format == '\0' ? format - 1 : format,
521                                  FMTDIR_ERROR);
522                         goto bad_format;
523                       }
524                   }
525                 else if (format[0] == 'F' && format[1] == 'A'
526                          && format[2] == 'S' && format[3] == 'T')
527                   {
528                     format += 4;
529                     if (format[0] == '8')
530                       {
531                         type |= FAT_SIZE_FAST8_T;
532                         format++;
533                       }
534                     else if (format[0] == '1' && format[1] == '6')
535                       {
536                         type |= FAT_SIZE_FAST16_T;
537                         format += 2;
538                       }
539                     else if (format[0] == '3' && format[1] == '2')
540                       {
541                         type |= FAT_SIZE_FAST32_T;
542                         format += 2;
543                       }
544                     else if (format[0] == '6' && format[1] == '4')
545                       {
546                         type |= FAT_SIZE_FAST64_T;
547                         format += 2;
548                       }
549                     else
550                       {
551                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
552                         FDI_SET (*format == '\0' ? format - 1 : format,
553                                  FMTDIR_ERROR);
554                         goto bad_format;
555                       }
556                   }
557                 else
558                   {
559                     if (format[0] == '8')
560                       {
561                         type |= FAT_SIZE_8_T;
562                         format++;
563                       }
564                     else if (format[0] == '1' && format[1] == '6')
565                       {
566                         type |= FAT_SIZE_16_T;
567                         format += 2;
568                       }
569                     else if (format[0] == '3' && format[1] == '2')
570                       {
571                         type |= FAT_SIZE_32_T;
572                         format += 2;
573                       }
574                     else if (format[0] == '6' && format[1] == '4')
575                       {
576                         type |= FAT_SIZE_64_T;
577                         format += 2;
578                       }
579                     else
580                       {
581                         *invalid_reason = INVALID_C99_MACRO (spec.directives);
582                         FDI_SET (*format == '\0' ? format - 1 : format,
583                                  FMTDIR_ERROR);
584                         goto bad_format;
585                       }
586                   }
587               }
588 
589             if (*format != '>')
590               {
591                 *invalid_reason = INVALID_ANGLE_BRACKET (spec.directives);
592                 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
593                 goto bad_format;
594               }
595 
596             spec.sysdep_directives[2 * spec.sysdep_directives_count + 1] = format + 1;
597             spec.sysdep_directives_count++;
598           }
599         else
600           {
601             /* Parse size.  */
602             size = 0;
603             for (;; format++)
604               {
605                 if (*format == 'h')
606                   {
607                     if (size & (FAT_SIZE_SHORT | FAT_SIZE_CHAR))
608                       size = FAT_SIZE_CHAR;
609                     else
610                       size = FAT_SIZE_SHORT;
611                   }
612                 else if (*format == 'l')
613                   {
614                     if (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG))
615                       size = FAT_SIZE_LONGLONG;
616                     else
617                       size = FAT_SIZE_LONG;
618                   }
619                 else if (*format == 'L')
620                   size = FAT_SIZE_LONGLONG;
621                 else if (*format == 'q')
622                   /* Old BSD 4.4 convention.  */
623                   size = FAT_SIZE_LONGLONG;
624                 else if (*format == 'j')
625                   size = FAT_SIZE_INTMAX_T;
626                 else if (*format == 'z' || *format == 'Z')
627                   /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
628                      because the warning facility in gcc-2.95.2 understands
629                      only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
630                   size = FAT_SIZE_SIZE_T;
631                 else if (*format == 't')
632                   size = FAT_SIZE_PTRDIFF_T;
633 #if defined _WIN32 && ! defined __CYGWIN__
634                 else if (SYSDEP_SEGMENTS_PROCESSED
635                          && *format == 'I'
636                          && format[1] == '6'
637                          && format[2] == '4')
638                   {
639                     size = FAT_SIZE_64_T;
640                     format += 2;
641                   }
642 #endif
643                 else
644                   break;
645               }
646 
647             switch (*format)
648               {
649               case '%':
650                 /* Programmers writing _("%2%") most often will not want to
651                    use this string as a c-format string, but rather as a
652                    literal or as a different kind of format string.  */
653                 if (format[-1] != '%')
654                   spec.unlikely_intentional = true;
655                 type = FAT_NONE;
656                 break;
657               case 'm': /* glibc extension */
658                 type = FAT_NONE;
659                 break;
660               case 'c':
661                 type = FAT_CHAR;
662                 type |= (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG)
663                          ? FAT_WIDE : 0);
664                 break;
665               case 'C': /* obsolete */
666                 type = FAT_CHAR | FAT_WIDE;
667                 break;
668               case 's':
669                 type = FAT_STRING;
670                 type |= (size & (FAT_SIZE_LONG | FAT_SIZE_LONGLONG)
671                          ? FAT_WIDE : 0);
672                 break;
673               case 'S': /* obsolete */
674                 type = FAT_STRING | FAT_WIDE;
675                 break;
676               case 'i': case 'd':
677                 type = FAT_INTEGER;
678                 type |= (size & FAT_SIZE_MASK);
679                 break;
680               case 'u': case 'o': case 'x': case 'X':
681                 type = FAT_INTEGER | FAT_UNSIGNED;
682                 type |= (size & FAT_SIZE_MASK);
683                 break;
684               case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
685               case 'a': case 'A':
686                 type = FAT_DOUBLE;
687                 type |= (size & FAT_SIZE_LONGLONG);
688                 break;
689               case '@':
690                 if (objc_extensions)
691                   {
692                     type = FAT_OBJC_OBJECT;
693                     break;
694                   }
695                 goto other;
696               case 'p':
697                 type = FAT_POINTER;
698                 break;
699               case 'n':
700                 type = FAT_COUNT_POINTER;
701                 type |= (size & FAT_SIZE_MASK);
702                 break;
703               other:
704               default:
705                 if (*format == '\0')
706                   {
707                     *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
708                     FDI_SET (format - 1, FMTDIR_ERROR);
709                   }
710                 else
711                   {
712                     *invalid_reason =
713                       INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
714                     FDI_SET (format, FMTDIR_ERROR);
715                   }
716                 goto bad_format;
717               }
718           }
719 
720         if (type != FAT_NONE)
721           {
722             if (number)
723               {
724                 /* Numbered argument.  */
725 
726                 /* Numbered and unnumbered specifications are exclusive.  */
727                 if (spec.unnumbered_arg_count > 0)
728                   {
729                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
730                     FDI_SET (format, FMTDIR_ERROR);
731                     goto bad_format;
732                   }
733 
734                 if (allocated == numbered_arg_count)
735                   {
736                     allocated = 2 * allocated + 1;
737                     numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg));
738                     IF_OOM (numbered, goto bad_format;)
739                   }
740                 numbered[numbered_arg_count].number = number;
741                 numbered[numbered_arg_count].type = type;
742                 numbered_arg_count++;
743               }
744             else
745               {
746                 /* Unnumbered argument.  */
747 
748                 /* Numbered and unnumbered specifications are exclusive.  */
749                 if (numbered_arg_count > 0)
750                   {
751                     *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
752                     FDI_SET (format, FMTDIR_ERROR);
753                     goto bad_format;
754                   }
755 
756                 if (allocated == spec.unnumbered_arg_count)
757                   {
758                     allocated = 2 * allocated + 1;
759                     spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, allocated * sizeof (struct unnumbered_arg));
760                     IF_OOM (spec.unnumbered, goto bad_format;)
761                   }
762                 spec.unnumbered[spec.unnumbered_arg_count].type = type;
763                 spec.unnumbered_arg_count++;
764               }
765           }
766 
767         FDI_SET (format, FMTDIR_END);
768 
769         format++;
770       }
771 
772   /* Sort the numbered argument array, and eliminate duplicates.  */
773   if (numbered_arg_count > 1)
774     {
775       unsigned int i, j;
776       bool err;
777 
778       qsort (numbered, numbered_arg_count,
779              sizeof (struct numbered_arg), numbered_arg_compare);
780 
781       /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
782       err = false;
783       for (i = j = 0; i < numbered_arg_count; i++)
784         if (j > 0 && numbered[i].number == numbered[j-1].number)
785           {
786             format_arg_type_t type1 = numbered[i].type;
787             format_arg_type_t type2 = numbered[j-1].type;
788             format_arg_type_t type_both;
789 
790             if (type1 == type2)
791               type_both = type1;
792             else
793               {
794                 /* Incompatible types.  */
795                 type_both = FAT_NONE;
796                 if (!err)
797                   *invalid_reason =
798                     INVALID_INCOMPATIBLE_ARG_TYPES (numbered[i].number);
799                 err = true;
800               }
801 
802             numbered[j-1].type = type_both;
803           }
804         else
805           {
806             if (j < i)
807               {
808                 numbered[j].number = numbered[i].number;
809                 numbered[j].type = numbered[i].type;
810               }
811             j++;
812           }
813       numbered_arg_count = j;
814       if (err)
815         /* *invalid_reason has already been set above.  */
816         goto bad_format;
817     }
818 
819   /* Verify that the format strings uses all arguments up to the highest
820      numbered one.  */
821   if (numbered_arg_count > 0)
822     {
823       unsigned int i;
824 
825       for (i = 0; i < numbered_arg_count; i++)
826         if (numbered[i].number != i + 1)
827           {
828             *invalid_reason = INVALID_IGNORED_ARGUMENT (numbered[i].number, i + 1);
829             goto bad_format;
830           }
831 
832       /* So now the numbered arguments array is equivalent to a sequence
833          of unnumbered arguments.  */
834       spec.unnumbered_arg_count = numbered_arg_count;
835       allocated = spec.unnumbered_arg_count;
836       spec.unnumbered = XNMALLOC (allocated, struct unnumbered_arg);
837       IF_OOM (spec.unnumbered, goto bad_format;)
838       for (i = 0; i < spec.unnumbered_arg_count; i++)
839         spec.unnumbered[i].type = numbered[i].type;
840       free (numbered);
841       numbered_arg_count = 0;
842     }
843 
844   *result = spec;
845   return result;
846 
847  bad_format:
848   if (numbered != NULL)
849     free (numbered);
850   if (spec.unnumbered != NULL)
851     free (spec.unnumbered);
852   if (spec.sysdep_directives != NULL)
853     free (spec.sysdep_directives);
854   return NULL;
855 }
856