Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gettext-0.26/gettext-tools/libgettextpo/printf-parse.c
Line
Count
Source
1
/* Formatted output to strings.
2
   Copyright (C) 1999-2000, 2002-2003, 2006-2025 Free Software Foundation, Inc.
3
4
   This file is free software: you can redistribute it and/or modify
5
   it under the terms of the GNU Lesser General Public License as
6
   published by the Free Software Foundation; either version 2.1 of the
7
   License, or (at your option) any later version.
8
9
   This file is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU Lesser General Public License for more details.
13
14
   You should have received a copy of the GNU Lesser General Public License
15
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16
17
/* This file can be parametrized with the following macros:
18
     CHAR_T             The element type of the format string.
19
     CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
20
                        in the format string are ASCII.
21
     DIRECTIVE          Structure denoting a format directive.
22
                        Depends on CHAR_T.
23
     DIRECTIVES         Structure denoting the set of format directives of a
24
                        format string.  Depends on CHAR_T.
25
     PRINTF_PARSE       Function that parses a format string.
26
                        Depends on CHAR_T.
27
     STATIC             Set to 'static' to declare the function static.
28
     ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
29
30
#ifndef PRINTF_PARSE
31
# include <config.h>
32
#endif
33
34
/* Specification.  */
35
#ifndef PRINTF_PARSE
36
# include "printf-parse.h"
37
#endif
38
39
/* Default parameters.  */
40
#ifndef PRINTF_PARSE
41
# define PRINTF_PARSE printf_parse
42
1.07M
# define CHAR_T char
43
11.0k
# define DIRECTIVE char_directive
44
# define DIRECTIVES char_directives
45
#endif
46
47
/* Get size_t, NULL.  */
48
#include <stddef.h>
49
50
/* Get intmax_t.  */
51
#include <stdint.h>
52
53
/* malloc(), realloc(), free().  */
54
#include <stdlib.h>
55
56
/* memcpy().  */
57
#include <string.h>
58
59
/* errno.  */
60
#include <errno.h>
61
62
/* Checked size_t computations.  */
63
#include "xsize.h"
64
65
#if CHAR_T_ONLY_ASCII
66
/* c_isascii().  */
67
# include "c-ctype.h"
68
#endif
69
70
#ifdef STATIC
71
STATIC
72
#endif
73
int
74
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
75
11.0k
{
76
11.0k
  const CHAR_T *cp = format;    /* pointer into format */
77
11.0k
  size_t arg_posn = 0;          /* number of regular arguments consumed */
78
11.0k
  size_t d_allocated;           /* allocated elements of d->dir */
79
11.0k
  size_t a_allocated;           /* allocated elements of a->arg */
80
11.0k
  size_t max_width_length = 0;
81
11.0k
  size_t max_precision_length = 0;
82
83
11.0k
  d->count = 0;
84
11.0k
  d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
85
11.0k
  d->dir = d->direct_alloc_dir;
86
87
11.0k
  a->count = 0;
88
11.0k
  a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
89
11.0k
  a->arg = a->direct_alloc_arg;
90
91
11.0k
#define REGISTER_ARG(_index_,_type_) \
92
11.0k
  {                                                                     \
93
11.0k
    size_t n = (_index_);                                               \
94
11.0k
    if (n >= a_allocated)                                               \
95
11.0k
      {                                                                 \
96
0
        size_t memory_size;                                             \
97
0
        argument *memory;                                               \
98
0
                                                                        \
99
0
        a_allocated = xtimes (a_allocated, 2);                          \
100
0
        if (a_allocated <= n)                                           \
101
0
          a_allocated = xsum (n, 1);                                    \
102
0
        memory_size = xtimes (a_allocated, sizeof (argument));          \
103
0
        if (size_overflow_p (memory_size))                              \
104
          /* Overflow, would lead to out of memory.  */                 \
105
0
          goto out_of_memory;                                           \
106
0
        memory = (argument *) (a->arg != a->direct_alloc_arg            \
107
0
                               ? realloc (a->arg, memory_size)          \
108
0
                               : malloc (memory_size));                 \
109
0
        if (memory == NULL)                                             \
110
          /* Out of memory.  */                                         \
111
0
          goto out_of_memory;                                           \
112
0
        if (a->arg == a->direct_alloc_arg)                              \
113
0
          memcpy (memory, a->arg, a->count * sizeof (argument));        \
114
0
        a->arg = memory;                                                \
115
0
      }                                                                 \
116
22.0k
    while (a->count <= n)                                               \
117
11.0k
      a->arg[a->count++].type = TYPE_NONE;                              \
118
11.0k
    if (a->arg[n].type == TYPE_NONE)                                    \
119
11.0k
      a->arg[n].type = (_type_);                                        \
120
11.0k
    else if (a->arg[n].type != (_type_))                                \
121
      /* Ambiguous type for positional argument.  */                    \
122
0
      goto error;                                                       \
123
11.0k
  }
124
125
1.08M
  while (*cp != '\0')
126
1.07M
    {
127
1.07M
      CHAR_T c = *cp++;
128
1.07M
      if (c == '%')
129
11.0k
        {
130
11.0k
          size_t arg_index = ARG_NONE;
131
11.0k
          DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
132
133
          /* Initialize the next directive.  */
134
11.0k
          dp->dir_start = cp - 1;
135
11.0k
          dp->flags = 0;
136
11.0k
          dp->width_start = NULL;
137
11.0k
          dp->width_end = NULL;
138
11.0k
          dp->width_arg_index = ARG_NONE;
139
11.0k
          dp->precision_start = NULL;
140
11.0k
          dp->precision_end = NULL;
141
11.0k
          dp->precision_arg_index = ARG_NONE;
142
11.0k
          dp->arg_index = ARG_NONE;
143
144
          /* Test for positional argument.  */
145
11.0k
          if (*cp >= '0' && *cp <= '9')
146
0
            {
147
0
              const CHAR_T *np;
148
149
0
              for (np = cp; *np >= '0' && *np <= '9'; np++)
150
0
                ;
151
0
              if (*np == '$')
152
0
                {
153
0
                  size_t n = 0;
154
155
0
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
156
0
                    n = xsum (xtimes (n, 10), *np - '0');
157
0
                  if (n == 0)
158
                    /* Positional argument 0.  */
159
0
                    goto error;
160
0
                  if (size_overflow_p (n))
161
                    /* n too large, would lead to out of memory later.  */
162
0
                    goto error;
163
0
                  arg_index = n - 1;
164
0
                  cp = np + 1;
165
0
                }
166
0
            }
167
168
          /* Read the flags.  */
169
11.0k
          for (;;)
170
11.0k
            {
171
11.0k
              if (*cp == '\'')
172
0
                {
173
0
                  dp->flags |= FLAG_GROUP;
174
0
                  cp++;
175
0
                }
176
11.0k
              else if (*cp == '-')
177
0
                {
178
0
                  dp->flags |= FLAG_LEFT;
179
0
                  cp++;
180
0
                }
181
11.0k
              else if (*cp == '+')
182
0
                {
183
0
                  dp->flags |= FLAG_SHOWSIGN;
184
0
                  cp++;
185
0
                }
186
11.0k
              else if (*cp == ' ')
187
0
                {
188
0
                  dp->flags |= FLAG_SPACE;
189
0
                  cp++;
190
0
                }
191
11.0k
              else if (*cp == '#')
192
0
                {
193
0
                  dp->flags |= FLAG_ALT;
194
0
                  cp++;
195
0
                }
196
11.0k
              else if (*cp == '0')
197
0
                {
198
0
                  dp->flags |= FLAG_ZERO;
199
0
                  cp++;
200
0
                }
201
11.0k
#if __GLIBC__ >= 2 && !defined __UCLIBC__
202
11.0k
              else if (*cp == 'I')
203
0
                {
204
0
                  dp->flags |= FLAG_LOCALIZED;
205
0
                  cp++;
206
0
                }
207
11.0k
#endif
208
11.0k
              else
209
11.0k
                break;
210
11.0k
            }
211
212
          /* Parse the field width.  */
213
11.0k
          if (*cp == '*')
214
0
            {
215
0
              dp->width_start = cp;
216
0
              cp++;
217
0
              dp->width_end = cp;
218
0
              if (max_width_length < 1)
219
0
                max_width_length = 1;
220
221
              /* Test for positional argument.  */
222
0
              if (*cp >= '0' && *cp <= '9')
223
0
                {
224
0
                  const CHAR_T *np;
225
226
0
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
227
0
                    ;
228
0
                  if (*np == '$')
229
0
                    {
230
0
                      size_t n = 0;
231
232
0
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
233
0
                        n = xsum (xtimes (n, 10), *np - '0');
234
0
                      if (n == 0)
235
                        /* Positional argument 0.  */
236
0
                        goto error;
237
0
                      if (size_overflow_p (n))
238
                        /* n too large, would lead to out of memory later.  */
239
0
                        goto error;
240
0
                      dp->width_arg_index = n - 1;
241
0
                      cp = np + 1;
242
0
                    }
243
0
                }
244
0
              if (dp->width_arg_index == ARG_NONE)
245
0
                {
246
0
                  dp->width_arg_index = arg_posn++;
247
0
                  if (dp->width_arg_index == ARG_NONE)
248
                    /* arg_posn wrapped around.  */
249
0
                    goto error;
250
0
                }
251
0
              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
252
0
            }
253
11.0k
          else if (*cp >= '0' && *cp <= '9')
254
0
            {
255
0
              size_t width_length;
256
257
0
              dp->width_start = cp;
258
0
              for (; *cp >= '0' && *cp <= '9'; cp++)
259
0
                ;
260
0
              dp->width_end = cp;
261
0
              width_length = dp->width_end - dp->width_start;
262
0
              if (max_width_length < width_length)
263
0
                max_width_length = width_length;
264
0
            }
265
266
          /* Parse the precision.  */
267
11.0k
          if (*cp == '.')
268
0
            {
269
0
              cp++;
270
0
              if (*cp == '*')
271
0
                {
272
0
                  dp->precision_start = cp - 1;
273
0
                  cp++;
274
0
                  dp->precision_end = cp;
275
0
                  if (max_precision_length < 2)
276
0
                    max_precision_length = 2;
277
278
                  /* Test for positional argument.  */
279
0
                  if (*cp >= '0' && *cp <= '9')
280
0
                    {
281
0
                      const CHAR_T *np;
282
283
0
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
284
0
                        ;
285
0
                      if (*np == '$')
286
0
                        {
287
0
                          size_t n = 0;
288
289
0
                          for (np = cp; *np >= '0' && *np <= '9'; np++)
290
0
                            n = xsum (xtimes (n, 10), *np - '0');
291
0
                          if (n == 0)
292
                            /* Positional argument 0.  */
293
0
                            goto error;
294
0
                          if (size_overflow_p (n))
295
                            /* n too large, would lead to out of memory
296
                               later.  */
297
0
                            goto error;
298
0
                          dp->precision_arg_index = n - 1;
299
0
                          cp = np + 1;
300
0
                        }
301
0
                    }
302
0
                  if (dp->precision_arg_index == ARG_NONE)
303
0
                    {
304
0
                      dp->precision_arg_index = arg_posn++;
305
0
                      if (dp->precision_arg_index == ARG_NONE)
306
                        /* arg_posn wrapped around.  */
307
0
                        goto error;
308
0
                    }
309
0
                  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
310
0
                }
311
0
              else
312
0
                {
313
0
                  size_t precision_length;
314
315
0
                  dp->precision_start = cp - 1;
316
0
                  for (; *cp >= '0' && *cp <= '9'; cp++)
317
0
                    ;
318
0
                  dp->precision_end = cp;
319
0
                  precision_length = dp->precision_end - dp->precision_start;
320
0
                  if (max_precision_length < precision_length)
321
0
                    max_precision_length = precision_length;
322
0
                }
323
0
            }
324
325
11.0k
          {
326
11.0k
            arg_type type;
327
328
            /* Parse argument type/size specifiers.  */
329
            /* Relevant for the conversion characters d, i.  */
330
11.0k
            arg_type signed_type = TYPE_INT;
331
            /* Relevant for the conversion characters b, o, u, x, X.  */
332
11.0k
            arg_type unsigned_type = TYPE_UINT;
333
            /* Relevant for the conversion characters n.  */
334
11.0k
            arg_type pointer_type = TYPE_COUNT_INT_POINTER;
335
            /* Relevant for the conversion characters a, A, e, E, f, F, g, G.  */
336
11.0k
            arg_type floatingpoint_type = TYPE_DOUBLE;
337
338
11.0k
            if (*cp == 'h')
339
0
              {
340
0
                if (cp[1] == 'h')
341
0
                  {
342
0
                    signed_type = TYPE_SCHAR;
343
0
                    unsigned_type = TYPE_UCHAR;
344
0
                    pointer_type = TYPE_COUNT_SCHAR_POINTER;
345
0
                    cp += 2;
346
0
                  }
347
0
                else
348
0
                  {
349
0
                    signed_type = TYPE_SHORT;
350
0
                    unsigned_type = TYPE_USHORT;
351
0
                    pointer_type = TYPE_COUNT_SHORT_POINTER;
352
0
                    cp++;
353
0
                  }
354
0
              }
355
11.0k
            else if (*cp == 'l')
356
0
              {
357
0
                if (cp[1] == 'l')
358
0
                  {
359
0
                    signed_type = TYPE_LONGLONGINT;
360
0
                    unsigned_type = TYPE_ULONGLONGINT;
361
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
362
                    /* For backward compatibility only.  */
363
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
364
0
                    cp += 2;
365
0
                  }
366
0
                else
367
0
                  {
368
0
                    signed_type = TYPE_LONGINT;
369
0
                    unsigned_type = TYPE_ULONGINT;
370
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
371
0
                    cp++;
372
0
                  }
373
0
              }
374
11.0k
            else if (*cp == 'j')
375
0
              {
376
0
                if (sizeof (intmax_t) > sizeof (long))
377
0
                  {
378
                    /* intmax_t = long long */
379
0
                    signed_type = TYPE_LONGLONGINT;
380
0
                    unsigned_type = TYPE_ULONGLONGINT;
381
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
382
                    /* For backward compatibility only.  */
383
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
384
0
                  }
385
0
                else if (sizeof (intmax_t) > sizeof (int))
386
0
                  {
387
                    /* intmax_t = long */
388
0
                    signed_type = TYPE_LONGINT;
389
0
                    unsigned_type = TYPE_ULONGINT;
390
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
391
0
                  }
392
0
                cp++;
393
0
              }
394
11.0k
            else if (*cp == 'z' || *cp == 'Z')
395
0
              {
396
                /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
397
                   because the warning facility in gcc-2.95.2 understands
398
                   only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
399
0
                if (sizeof (size_t) > sizeof (long))
400
0
                  {
401
                    /* size_t = unsigned long long */
402
0
                    signed_type = TYPE_LONGLONGINT;
403
0
                    unsigned_type = TYPE_ULONGLONGINT;
404
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
405
                    /* For backward compatibility only.  */
406
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
407
0
                  }
408
0
                else if (sizeof (size_t) > sizeof (int))
409
0
                  {
410
                    /* size_t = unsigned long */
411
0
                    signed_type = TYPE_LONGINT;
412
0
                    unsigned_type = TYPE_ULONGINT;
413
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
414
0
                  }
415
0
                cp++;
416
0
              }
417
11.0k
            else if (*cp == 't')
418
0
              {
419
0
                if (sizeof (ptrdiff_t) > sizeof (long))
420
0
                  {
421
                    /* ptrdiff_t = long long */
422
0
                    signed_type = TYPE_LONGLONGINT;
423
0
                    unsigned_type = TYPE_ULONGLONGINT;
424
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
425
                    /* For backward compatibility only.  */
426
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
427
0
                  }
428
0
                else if (sizeof (ptrdiff_t) > sizeof (int))
429
0
                  {
430
                    /* ptrdiff_t = long */
431
0
                    signed_type = TYPE_LONGINT;
432
0
                    unsigned_type = TYPE_ULONGINT;
433
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
434
0
                  }
435
0
                cp++;
436
0
              }
437
11.0k
            else if (*cp == 'w')
438
0
              {
439
                /* wN and wfN are standardized in ISO C 23.  */
440
0
                if (cp[1] == 'f')
441
0
                  {
442
0
                    if (cp[2] == '8')
443
0
                      {
444
0
                        signed_type = TYPE_INT_FAST8_T;
445
0
                        unsigned_type = TYPE_UINT_FAST8_T;
446
0
                        pointer_type = TYPE_COUNT_INT_FAST8_T_POINTER;
447
0
                        cp += 3;
448
0
                      }
449
0
                    else if (cp[2] == '1' && cp[3] == '6')
450
0
                      {
451
0
                        signed_type = TYPE_INT_FAST16_T;
452
0
                        unsigned_type = TYPE_UINT_FAST16_T;
453
0
                        pointer_type = TYPE_COUNT_INT_FAST16_T_POINTER;
454
0
                        cp += 4;
455
0
                      }
456
0
                    else if (cp[2] == '3' && cp[3] == '2')
457
0
                      {
458
0
                        signed_type = TYPE_INT_FAST32_T;
459
0
                        unsigned_type = TYPE_UINT_FAST32_T;
460
0
                        pointer_type = TYPE_COUNT_INT_FAST32_T_POINTER;
461
0
                        cp += 4;
462
0
                      }
463
0
                    else if (cp[2] == '6' && cp[3] == '4')
464
0
                      {
465
0
                        signed_type = TYPE_INT_FAST64_T;
466
0
                        unsigned_type = TYPE_UINT_FAST64_T;
467
0
                        pointer_type = TYPE_COUNT_INT_FAST64_T_POINTER;
468
0
                        cp += 4;
469
0
                      }
470
0
                  }
471
0
                else
472
0
                  {
473
0
                    if (cp[1] == '8')
474
0
                      {
475
0
                        signed_type = TYPE_INT8_T;
476
0
                        unsigned_type = TYPE_UINT8_T;
477
0
                        pointer_type = TYPE_COUNT_INT8_T_POINTER;
478
0
                        cp += 2;
479
0
                      }
480
0
                    else if (cp[1] == '1' && cp[2] == '6')
481
0
                      {
482
0
                        signed_type = TYPE_INT16_T;
483
0
                        unsigned_type = TYPE_UINT16_T;
484
0
                        pointer_type = TYPE_COUNT_INT16_T_POINTER;
485
0
                        cp += 3;
486
0
                      }
487
0
                    else if (cp[1] == '3' && cp[2] == '2')
488
0
                      {
489
0
                        signed_type = TYPE_INT32_T;
490
0
                        unsigned_type = TYPE_UINT32_T;
491
0
                        pointer_type = TYPE_COUNT_INT32_T_POINTER;
492
0
                        cp += 3;
493
0
                      }
494
0
                    else if (cp[1] == '6' && cp[2] == '4')
495
0
                      {
496
0
                        signed_type = TYPE_INT64_T;
497
0
                        unsigned_type = TYPE_UINT64_T;
498
0
                        pointer_type = TYPE_COUNT_INT64_T_POINTER;
499
0
                        cp += 3;
500
0
                      }
501
0
                  }
502
0
              }
503
11.0k
            else if (*cp == 'L')
504
0
              {
505
0
                signed_type = TYPE_LONGLONGINT;
506
0
                unsigned_type = TYPE_ULONGLONGINT;
507
0
                pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
508
0
                floatingpoint_type = TYPE_LONGDOUBLE;
509
0
                cp++;
510
0
              }
511
#if defined __APPLE__ && defined __MACH__
512
            /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
513
               We cannot change it to "lld" because PRIdMAX must also
514
               be understood by the system's printf routines.  */
515
            else if (*cp == 'q')
516
              {
517
                if (64 / 8 > sizeof (long))
518
                  {
519
                    /* int64_t = long long */
520
                    signed_type = TYPE_LONGLONGINT;
521
                    unsigned_type = TYPE_ULONGLONGINT;
522
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
523
                    /* For backward compatibility only.  */
524
                    floatingpoint_type = TYPE_LONGDOUBLE;
525
                  }
526
                else
527
                  {
528
                    /* int64_t = long */
529
                    signed_type = TYPE_LONGINT;
530
                    unsigned_type = TYPE_ULONGINT;
531
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
532
                  }
533
                cp++;
534
              }
535
#endif
536
#if defined _WIN32 && ! defined __CYGWIN__
537
            /* On native Windows, PRIdMAX is defined as "I64d".
538
               We cannot change it to "lld" because PRIdMAX must also
539
               be understood by the system's printf routines.  */
540
            else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
541
              {
542
                if (64 / 8 > sizeof (long))
543
                  {
544
                    /* __int64_t = long long */
545
                    signed_type = TYPE_LONGLONGINT;
546
                    unsigned_type = TYPE_ULONGLONGINT;
547
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
548
                    /* For backward compatibility only.  */
549
                    floatingpoint_type = TYPE_LONGDOUBLE;
550
                  }
551
                else
552
                  {
553
                    /* __int64_t = long */
554
                    signed_type = TYPE_LONGINT;
555
                    unsigned_type = TYPE_ULONGINT;
556
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
557
                  }
558
                cp += 3;
559
              }
560
#endif
561
11.0k
            (void) pointer_type;
562
563
            /* Read the conversion character.  */
564
11.0k
            c = *cp++;
565
11.0k
            switch (c)
566
11.0k
              {
567
0
              case 'd': case 'i':
568
0
                type = signed_type;
569
0
                break;
570
0
              case 'b': case 'o': case 'u': case 'x': case 'X':
571
              #if SUPPORT_GNU_PRINTF_DIRECTIVES \
572
                  || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
573
              case 'B':
574
              #endif
575
0
                type = unsigned_type;
576
0
                break;
577
0
              case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
578
0
              case 'a': case 'A':
579
0
                type = floatingpoint_type;
580
0
                break;
581
0
              case 'c':
582
0
                if (signed_type == TYPE_LONGINT
583
                    /* For backward compatibility only.  */
584
0
                    || signed_type == TYPE_LONGLONGINT)
585
0
#if HAVE_WINT_T
586
0
                  type = TYPE_WIDE_CHAR;
587
#else
588
                  goto error;
589
#endif
590
0
                else
591
0
                  type = TYPE_CHAR;
592
0
                break;
593
0
#if HAVE_WINT_T
594
0
              case 'C':
595
0
                type = TYPE_WIDE_CHAR;
596
0
                c = 'c';
597
0
                break;
598
0
#endif
599
11.0k
              case 's':
600
11.0k
                if (signed_type == TYPE_LONGINT
601
                    /* For backward compatibility only.  */
602
11.0k
                    || signed_type == TYPE_LONGLONGINT)
603
0
                  type = TYPE_WIDE_STRING;
604
11.0k
                else
605
11.0k
                  type = TYPE_STRING;
606
11.0k
                break;
607
0
              case 'S':
608
0
                type = TYPE_WIDE_STRING;
609
0
                c = 's';
610
0
                break;
611
0
              case 'p':
612
0
                type = TYPE_POINTER;
613
0
                break;
614
#if NEED_PRINTF_WITH_N_DIRECTIVE
615
              case 'n':
616
                type = pointer_type;
617
                break;
618
#endif
619
#if ENABLE_UNISTDIO
620
              /* The unistdio extensions.  */
621
              case 'U':
622
                if (signed_type == TYPE_LONGLONGINT)
623
                  type = TYPE_U32_STRING;
624
                else if (signed_type == TYPE_LONGINT)
625
                  type = TYPE_U16_STRING;
626
                else
627
                  type = TYPE_U8_STRING;
628
                break;
629
#endif
630
0
              case '%':
631
0
                type = TYPE_NONE;
632
0
                break;
633
0
              default:
634
                /* Unknown conversion character.  */
635
0
                goto error;
636
11.0k
              }
637
638
11.0k
            if (type != TYPE_NONE)
639
11.0k
              {
640
11.0k
                dp->arg_index = arg_index;
641
11.0k
                if (dp->arg_index == ARG_NONE)
642
11.0k
                  {
643
11.0k
                    dp->arg_index = arg_posn++;
644
11.0k
                    if (dp->arg_index == ARG_NONE)
645
                      /* arg_posn wrapped around.  */
646
0
                      goto error;
647
11.0k
                  }
648
22.0k
                REGISTER_ARG (dp->arg_index, type);
649
11.0k
              }
650
11.0k
            dp->conversion = c;
651
11.0k
            dp->dir_end = cp;
652
11.0k
          }
653
654
0
          d->count++;
655
11.0k
          if (d->count >= d_allocated)
656
0
            {
657
0
              size_t memory_size;
658
0
              DIRECTIVE *memory;
659
660
0
              d_allocated = xtimes (d_allocated, 2);
661
0
              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
662
0
              if (size_overflow_p (memory_size))
663
                /* Overflow, would lead to out of memory.  */
664
0
                goto out_of_memory;
665
0
              memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
666
0
                                      ? realloc (d->dir, memory_size)
667
0
                                      : malloc (memory_size));
668
0
              if (memory == NULL)
669
                /* Out of memory.  */
670
0
                goto out_of_memory;
671
0
              if (d->dir == d->direct_alloc_dir)
672
0
                memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
673
0
              d->dir = memory;
674
0
            }
675
11.0k
        }
676
#if CHAR_T_ONLY_ASCII
677
      else if (!c_isascii (c))
678
        {
679
          /* Non-ASCII character.  Not supported.  */
680
          goto error;
681
        }
682
#endif
683
1.07M
    }
684
11.0k
  d->dir[d->count].dir_start = cp;
685
686
11.0k
  d->max_width_length = max_width_length;
687
11.0k
  d->max_precision_length = max_precision_length;
688
11.0k
  return 0;
689
690
0
error:
691
0
  if (a->arg != a->direct_alloc_arg)
692
0
    free (a->arg);
693
0
  if (d->dir != d->direct_alloc_dir)
694
0
    free (d->dir);
695
0
  errno = EINVAL;
696
0
  return -1;
697
698
0
out_of_memory:
699
0
  if (a->arg != a->direct_alloc_arg)
700
0
    free (a->arg);
701
0
  if (d->dir != d->direct_alloc_dir)
702
0
    free (d->dir);
703
0
  errno = ENOMEM;
704
0
  return -1;
705
11.0k
}
706
707
#undef PRINTF_PARSE
708
#undef DIRECTIVES
709
#undef DIRECTIVE
710
#undef CHAR_T_ONLY_ASCII
711
#undef CHAR_T