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