Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gettext/gettext-tools/libgettextpo/printf-parse.c
Line
Count
Source
1
/* Formatted output to strings.
2
   Copyright (C) 1999-2000, 2002-2003, 2006-2026 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
898k
# define CHAR_T char
43
9.16k
# 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
9.16k
{
76
9.16k
  const CHAR_T *cp = format;    /* pointer into format */
77
9.16k
  size_t arg_posn = 0;          /* number of regular arguments consumed */
78
9.16k
  size_t d_allocated;           /* allocated elements of d->dir */
79
9.16k
  size_t a_allocated;           /* allocated elements of a->arg */
80
9.16k
  size_t max_width_length = 0;
81
9.16k
  size_t max_precision_length = 0;
82
83
9.16k
  d->count = 0;
84
9.16k
  d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
85
9.16k
  d->dir = d->direct_alloc_dir;
86
87
9.16k
  a->count = 0;
88
9.16k
  a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
89
9.16k
  a->arg = a->direct_alloc_arg;
90
91
9.16k
#define REGISTER_ARG(_index_,_type_) \
92
9.16k
  {                                                                     \
93
9.16k
    size_t n = (_index_);                                               \
94
9.16k
    if (n >= a_allocated)                                               \
95
9.16k
      {                                                                 \
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
18.3k
    while (a->count <= n)                                               \
117
9.16k
      a->arg[a->count++].type = TYPE_NONE;                              \
118
9.16k
    if (a->arg[n].type == TYPE_NONE)                                    \
119
9.16k
      a->arg[n].type = (_type_);                                        \
120
9.16k
    else if (a->arg[n].type != (_type_))                                \
121
      /* Ambiguous type for positional argument.  */                    \
122
0
      goto error;                                                       \
123
9.16k
  }
124
125
907k
  while (*cp != '\0')
126
898k
    {
127
898k
      CHAR_T c = *cp++;
128
898k
      if (c == '%')
129
9.16k
        {
130
9.16k
          size_t arg_index = ARG_NONE;
131
9.16k
          DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
132
133
          /* Initialize the next directive.  */
134
9.16k
          dp->dir_start = cp - 1;
135
9.16k
          dp->flags = 0;
136
9.16k
          dp->width_start = NULL;
137
9.16k
          dp->width_end = NULL;
138
9.16k
          dp->width_arg_index = ARG_NONE;
139
9.16k
          dp->precision_start = NULL;
140
9.16k
          dp->precision_end = NULL;
141
9.16k
          dp->precision_arg_index = ARG_NONE;
142
9.16k
          dp->arg_index = ARG_NONE;
143
144
          /* Test for positional argument.  */
145
9.16k
          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
9.16k
          for (;;)
170
9.16k
            {
171
9.16k
              if (*cp == '\'')
172
0
                {
173
0
                  dp->flags |= FLAG_GROUP;
174
0
                  cp++;
175
0
                }
176
9.16k
              else if (*cp == '-')
177
0
                {
178
0
                  dp->flags |= FLAG_LEFT;
179
0
                  cp++;
180
0
                }
181
9.16k
              else if (*cp == '+')
182
0
                {
183
0
                  dp->flags |= FLAG_SHOWSIGN;
184
0
                  cp++;
185
0
                }
186
9.16k
              else if (*cp == ' ')
187
0
                {
188
0
                  dp->flags |= FLAG_SPACE;
189
0
                  cp++;
190
0
                }
191
9.16k
              else if (*cp == '#')
192
0
                {
193
0
                  dp->flags |= FLAG_ALT;
194
0
                  cp++;
195
0
                }
196
9.16k
              else if (*cp == '0')
197
0
                {
198
0
                  dp->flags |= FLAG_ZERO;
199
0
                  cp++;
200
0
                }
201
9.16k
#if __GLIBC__ >= 2 && !defined __UCLIBC__
202
9.16k
              else if (*cp == 'I')
203
0
                {
204
0
                  dp->flags |= FLAG_LOCALIZED;
205
0
                  cp++;
206
0
                }
207
9.16k
#endif
208
9.16k
              else
209
9.16k
                break;
210
9.16k
            }
211
212
          /* Parse the field width.  */
213
9.16k
          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
9.16k
          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
9.16k
          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
9.16k
          {
326
            /* Parse argument type/size specifiers.  */
327
            /* Relevant for the conversion characters d, i.  */
328
9.16k
            arg_type signed_type = TYPE_INT;
329
            /* Relevant for the conversion characters b, o, u, x, X.  */
330
9.16k
            arg_type unsigned_type = TYPE_UINT;
331
            /* Relevant for the conversion characters n.  */
332
9.16k
            arg_type pointer_type = TYPE_COUNT_INT_POINTER;
333
            /* Relevant for the conversion characters a, A, e, E, f, F, g, G.  */
334
9.16k
            arg_type floatingpoint_type = TYPE_DOUBLE;
335
336
9.16k
            if (*cp == 'h')
337
0
              {
338
0
                if (cp[1] == 'h')
339
0
                  {
340
0
                    signed_type = TYPE_SCHAR;
341
0
                    unsigned_type = TYPE_UCHAR;
342
0
                    pointer_type = TYPE_COUNT_SCHAR_POINTER;
343
0
                    cp += 2;
344
0
                  }
345
0
                else
346
0
                  {
347
0
                    signed_type = TYPE_SHORT;
348
0
                    unsigned_type = TYPE_USHORT;
349
0
                    pointer_type = TYPE_COUNT_SHORT_POINTER;
350
0
                    cp++;
351
0
                  }
352
0
              }
353
9.16k
            else if (*cp == 'l')
354
0
              {
355
0
                if (cp[1] == 'l')
356
0
                  {
357
0
                    signed_type = TYPE_LONGLONGINT;
358
0
                    unsigned_type = TYPE_ULONGLONGINT;
359
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
360
                    /* For backward compatibility only.  */
361
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
362
0
                    cp += 2;
363
0
                  }
364
0
                else
365
0
                  {
366
0
                    signed_type = TYPE_LONGINT;
367
0
                    unsigned_type = TYPE_ULONGINT;
368
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
369
0
                    cp++;
370
0
                  }
371
0
              }
372
9.16k
            else if (*cp == 'j')
373
0
              {
374
0
                if (sizeof (intmax_t) > sizeof (long))
375
0
                  {
376
                    /* intmax_t = long long */
377
0
                    signed_type = TYPE_LONGLONGINT;
378
0
                    unsigned_type = TYPE_ULONGLONGINT;
379
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
380
                    /* For backward compatibility only.  */
381
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
382
0
                  }
383
0
                else if (sizeof (intmax_t) > sizeof (int))
384
0
                  {
385
                    /* intmax_t = long */
386
0
                    signed_type = TYPE_LONGINT;
387
0
                    unsigned_type = TYPE_ULONGINT;
388
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
389
0
                  }
390
0
                cp++;
391
0
              }
392
9.16k
            else if (*cp == 'z' || *cp == 'Z')
393
0
              {
394
                /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
395
                   because the warning facility in gcc-2.95.2 understands
396
                   only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
397
0
                if (sizeof (size_t) > sizeof (long))
398
0
                  {
399
                    /* size_t = unsigned long long */
400
0
                    signed_type = TYPE_LONGLONGINT;
401
0
                    unsigned_type = TYPE_ULONGLONGINT;
402
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
403
                    /* For backward compatibility only.  */
404
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
405
0
                  }
406
0
                else if (sizeof (size_t) > sizeof (int))
407
0
                  {
408
                    /* size_t = unsigned long */
409
0
                    signed_type = TYPE_LONGINT;
410
0
                    unsigned_type = TYPE_ULONGINT;
411
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
412
0
                  }
413
0
                cp++;
414
0
              }
415
9.16k
            else if (*cp == 't')
416
0
              {
417
0
                if (sizeof (ptrdiff_t) > sizeof (long))
418
0
                  {
419
                    /* ptrdiff_t = long long */
420
0
                    signed_type = TYPE_LONGLONGINT;
421
0
                    unsigned_type = TYPE_ULONGLONGINT;
422
0
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
423
                    /* For backward compatibility only.  */
424
0
                    floatingpoint_type = TYPE_LONGDOUBLE;
425
0
                  }
426
0
                else if (sizeof (ptrdiff_t) > sizeof (int))
427
0
                  {
428
                    /* ptrdiff_t = long */
429
0
                    signed_type = TYPE_LONGINT;
430
0
                    unsigned_type = TYPE_ULONGINT;
431
0
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
432
0
                  }
433
0
                cp++;
434
0
              }
435
9.16k
            else if (*cp == 'w')
436
0
              {
437
                /* wN and wfN are standardized in ISO C 23.  */
438
0
                if (cp[1] == 'f')
439
0
                  {
440
0
                    if (cp[2] == '8')
441
0
                      {
442
0
                        signed_type = TYPE_INT_FAST8_T;
443
0
                        unsigned_type = TYPE_UINT_FAST8_T;
444
0
                        pointer_type = TYPE_COUNT_INT_FAST8_T_POINTER;
445
0
                        cp += 3;
446
0
                      }
447
0
                    else if (cp[2] == '1' && cp[3] == '6')
448
0
                      {
449
0
                        signed_type = TYPE_INT_FAST16_T;
450
0
                        unsigned_type = TYPE_UINT_FAST16_T;
451
0
                        pointer_type = TYPE_COUNT_INT_FAST16_T_POINTER;
452
0
                        cp += 4;
453
0
                      }
454
0
                    else if (cp[2] == '3' && cp[3] == '2')
455
0
                      {
456
0
                        signed_type = TYPE_INT_FAST32_T;
457
0
                        unsigned_type = TYPE_UINT_FAST32_T;
458
0
                        pointer_type = TYPE_COUNT_INT_FAST32_T_POINTER;
459
0
                        cp += 4;
460
0
                      }
461
0
                    else if (cp[2] == '6' && cp[3] == '4')
462
0
                      {
463
0
                        signed_type = TYPE_INT_FAST64_T;
464
0
                        unsigned_type = TYPE_UINT_FAST64_T;
465
0
                        pointer_type = TYPE_COUNT_INT_FAST64_T_POINTER;
466
0
                        cp += 4;
467
0
                      }
468
0
                  }
469
0
                else
470
0
                  {
471
0
                    if (cp[1] == '8')
472
0
                      {
473
0
                        signed_type = TYPE_INT8_T;
474
0
                        unsigned_type = TYPE_UINT8_T;
475
0
                        pointer_type = TYPE_COUNT_INT8_T_POINTER;
476
0
                        cp += 2;
477
0
                      }
478
0
                    else if (cp[1] == '1' && cp[2] == '6')
479
0
                      {
480
0
                        signed_type = TYPE_INT16_T;
481
0
                        unsigned_type = TYPE_UINT16_T;
482
0
                        pointer_type = TYPE_COUNT_INT16_T_POINTER;
483
0
                        cp += 3;
484
0
                      }
485
0
                    else if (cp[1] == '3' && cp[2] == '2')
486
0
                      {
487
0
                        signed_type = TYPE_INT32_T;
488
0
                        unsigned_type = TYPE_UINT32_T;
489
0
                        pointer_type = TYPE_COUNT_INT32_T_POINTER;
490
0
                        cp += 3;
491
0
                      }
492
0
                    else if (cp[1] == '6' && cp[2] == '4')
493
0
                      {
494
0
                        signed_type = TYPE_INT64_T;
495
0
                        unsigned_type = TYPE_UINT64_T;
496
0
                        pointer_type = TYPE_COUNT_INT64_T_POINTER;
497
0
                        cp += 3;
498
0
                      }
499
0
                  }
500
0
              }
501
9.16k
            else if (*cp == 'L')
502
0
              {
503
0
                signed_type = TYPE_LONGLONGINT;
504
0
                unsigned_type = TYPE_ULONGLONGINT;
505
0
                pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
506
0
                floatingpoint_type = TYPE_LONGDOUBLE;
507
0
                cp++;
508
0
              }
509
#if defined __APPLE__ && defined __MACH__
510
            /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
511
               We cannot change it to "lld" because PRIdMAX must also
512
               be understood by the system's printf routines.  */
513
            else if (*cp == 'q')
514
              {
515
                if (64 / 8 > sizeof (long))
516
                  {
517
                    /* int64_t = long long */
518
                    signed_type = TYPE_LONGLONGINT;
519
                    unsigned_type = TYPE_ULONGLONGINT;
520
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
521
                    /* For backward compatibility only.  */
522
                    floatingpoint_type = TYPE_LONGDOUBLE;
523
                  }
524
                else
525
                  {
526
                    /* int64_t = long */
527
                    signed_type = TYPE_LONGINT;
528
                    unsigned_type = TYPE_ULONGINT;
529
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
530
                  }
531
                cp++;
532
              }
533
#endif
534
#if defined _WIN32 && ! defined __CYGWIN__
535
            /* On native Windows, PRIdMAX is defined as "I64d".
536
               We cannot change it to "lld" because PRIdMAX must also
537
               be understood by the system's printf routines.  */
538
            else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
539
              {
540
                if (64 / 8 > sizeof (long))
541
                  {
542
                    /* __int64_t = long long */
543
                    signed_type = TYPE_LONGLONGINT;
544
                    unsigned_type = TYPE_ULONGLONGINT;
545
                    pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
546
                    /* For backward compatibility only.  */
547
                    floatingpoint_type = TYPE_LONGDOUBLE;
548
                  }
549
                else
550
                  {
551
                    /* __int64_t = long */
552
                    signed_type = TYPE_LONGINT;
553
                    unsigned_type = TYPE_ULONGINT;
554
                    pointer_type = TYPE_COUNT_LONGINT_POINTER;
555
                  }
556
                cp += 3;
557
              }
558
#endif
559
9.16k
            (void) pointer_type;
560
561
            /* Read the conversion character.  */
562
9.16k
            arg_type type;
563
9.16k
            c = *cp++;
564
9.16k
            switch (c)
565
9.16k
              {
566
0
              case 'd': case 'i':
567
0
                type = signed_type;
568
0
                break;
569
0
              case 'b': case 'o': case 'u': case 'x': case 'X':
570
              #if SUPPORT_GNU_PRINTF_DIRECTIVES \
571
                  || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
572
              case 'B':
573
              #endif
574
0
                type = unsigned_type;
575
0
                break;
576
0
              case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
577
0
              case 'a': case 'A':
578
0
                type = floatingpoint_type;
579
0
                break;
580
0
              case 'c':
581
0
                if (signed_type == TYPE_LONGINT
582
                    /* For backward compatibility only.  */
583
0
                    || signed_type == TYPE_LONGLONGINT)
584
0
#if HAVE_WINT_T
585
0
                  type = TYPE_WIDE_CHAR;
586
#else
587
                  goto error;
588
#endif
589
0
                else
590
0
                  type = TYPE_CHAR;
591
0
                break;
592
0
#if HAVE_WINT_T
593
0
              case 'C':
594
0
                type = TYPE_WIDE_CHAR;
595
0
                c = 'c';
596
0
                break;
597
0
#endif
598
9.16k
              case 's':
599
9.16k
                if (signed_type == TYPE_LONGINT
600
                    /* For backward compatibility only.  */
601
9.16k
                    || signed_type == TYPE_LONGLONGINT)
602
0
                  type = TYPE_WIDE_STRING;
603
9.16k
                else
604
9.16k
                  type = TYPE_STRING;
605
9.16k
                break;
606
0
              case 'S':
607
0
                type = TYPE_WIDE_STRING;
608
0
                c = 's';
609
0
                break;
610
0
              case 'p':
611
0
                type = TYPE_POINTER;
612
0
                break;
613
#if NEED_PRINTF_WITH_N_DIRECTIVE
614
              case 'n':
615
                type = pointer_type;
616
                break;
617
#endif
618
#if ENABLE_UNISTDIO
619
              /* The unistdio extensions.  */
620
              case 'U':
621
                if (signed_type == TYPE_LONGLONGINT)
622
                  type = TYPE_U32_STRING;
623
                else if (signed_type == TYPE_LONGINT)
624
                  type = TYPE_U16_STRING;
625
                else
626
                  type = TYPE_U8_STRING;
627
                break;
628
#endif
629
0
              case '%':
630
0
                type = TYPE_NONE;
631
0
                break;
632
0
              default:
633
                /* Unknown conversion character.  */
634
0
                goto error;
635
9.16k
              }
636
637
9.16k
            if (type != TYPE_NONE)
638
9.16k
              {
639
9.16k
                dp->arg_index = arg_index;
640
9.16k
                if (dp->arg_index == ARG_NONE)
641
9.16k
                  {
642
9.16k
                    dp->arg_index = arg_posn++;
643
9.16k
                    if (dp->arg_index == ARG_NONE)
644
                      /* arg_posn wrapped around.  */
645
0
                      goto error;
646
9.16k
                  }
647
18.3k
                REGISTER_ARG (dp->arg_index, type);
648
9.16k
              }
649
9.16k
            dp->conversion = c;
650
9.16k
            dp->dir_end = cp;
651
9.16k
          }
652
653
0
          d->count++;
654
9.16k
          if (d->count >= d_allocated)
655
0
            {
656
0
              d_allocated = xtimes (d_allocated, 2);
657
0
              size_t memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
658
0
              if (size_overflow_p (memory_size))
659
                /* Overflow, would lead to out of memory.  */
660
0
                goto out_of_memory;
661
0
              DIRECTIVE *memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
662
0
                                                 ? realloc (d->dir, memory_size)
663
0
                                                 : malloc (memory_size));
664
0
              if (memory == NULL)
665
                /* Out of memory.  */
666
0
                goto out_of_memory;
667
0
              if (d->dir == d->direct_alloc_dir)
668
0
                memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
669
0
              d->dir = memory;
670
0
            }
671
9.16k
        }
672
#if CHAR_T_ONLY_ASCII
673
      else if (!c_isascii (c))
674
        {
675
          /* Non-ASCII character.  Not supported.  */
676
          goto error;
677
        }
678
#endif
679
898k
    }
680
9.16k
  d->dir[d->count].dir_start = cp;
681
682
9.16k
  d->max_width_length = max_width_length;
683
9.16k
  d->max_precision_length = max_precision_length;
684
9.16k
  return 0;
685
686
0
error:
687
0
  if (a->arg != a->direct_alloc_arg)
688
0
    free (a->arg);
689
0
  if (d->dir != d->direct_alloc_dir)
690
0
    free (d->dir);
691
0
  errno = EINVAL;
692
0
  return -1;
693
694
0
out_of_memory:
695
0
  if (a->arg != a->direct_alloc_arg)
696
0
    free (a->arg);
697
0
  if (d->dir != d->direct_alloc_dir)
698
0
    free (d->dir);
699
0
  errno = ENOMEM;
700
0
  return -1;
701
9.16k
}
702
703
#undef PRINTF_PARSE
704
#undef DIRECTIVES
705
#undef DIRECTIVE
706
#undef CHAR_T_ONLY_ASCII
707
#undef CHAR_T