root/maint/gnulib/lib/printf-parse.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PRINTF_PARSE

   1 /* Formatted output to strings.
   2    Copyright (C) 1999-2000, 2002-2003, 2006-2021 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 # define CHAR_T char
  43 # 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76   const CHAR_T *cp = format;    /* pointer into format */
  77   size_t arg_posn = 0;          /* number of regular arguments consumed */
  78   size_t d_allocated;           /* allocated elements of d->dir */
  79   size_t a_allocated;           /* allocated elements of a->arg */
  80   size_t max_width_length = 0;
  81   size_t max_precision_length = 0;
  82 
  83   d->count = 0;
  84   d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
  85   d->dir = d->direct_alloc_dir;
  86 
  87   a->count = 0;
  88   a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
  89   a->arg = a->direct_alloc_arg;
  90 
  91 #define REGISTER_ARG(_index_,_type_) \
  92   {                                                                     \
  93     size_t n = (_index_);                                               \
  94     if (n >= a_allocated)                                               \
  95       {                                                                 \
  96         size_t memory_size;                                             \
  97         argument *memory;                                               \
  98                                                                         \
  99         a_allocated = xtimes (a_allocated, 2);                          \
 100         if (a_allocated <= n)                                           \
 101           a_allocated = xsum (n, 1);                                    \
 102         memory_size = xtimes (a_allocated, sizeof (argument));          \
 103         if (size_overflow_p (memory_size))                              \
 104           /* Overflow, would lead to out of memory.  */                 \
 105           goto out_of_memory;                                           \
 106         memory = (argument *) (a->arg != a->direct_alloc_arg            \
 107                                ? realloc (a->arg, memory_size)          \
 108                                : malloc (memory_size));                 \
 109         if (memory == NULL)                                             \
 110           /* Out of memory.  */                                         \
 111           goto out_of_memory;                                           \
 112         if (a->arg == a->direct_alloc_arg)                              \
 113           memcpy (memory, a->arg, a->count * sizeof (argument));        \
 114         a->arg = memory;                                                \
 115       }                                                                 \
 116     while (a->count <= n)                                               \
 117       a->arg[a->count++].type = TYPE_NONE;                              \
 118     if (a->arg[n].type == TYPE_NONE)                                    \
 119       a->arg[n].type = (_type_);                                        \
 120     else if (a->arg[n].type != (_type_))                                \
 121       /* Ambiguous type for positional argument.  */                    \
 122       goto error;                                                       \
 123   }
 124 
 125   while (*cp != '\0')
 126     {
 127       CHAR_T c = *cp++;
 128       if (c == '%')
 129         {
 130           size_t arg_index = ARG_NONE;
 131           DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
 132 
 133           /* Initialize the next directive.  */
 134           dp->dir_start = cp - 1;
 135           dp->flags = 0;
 136           dp->width_start = NULL;
 137           dp->width_end = NULL;
 138           dp->width_arg_index = ARG_NONE;
 139           dp->precision_start = NULL;
 140           dp->precision_end = NULL;
 141           dp->precision_arg_index = ARG_NONE;
 142           dp->arg_index = ARG_NONE;
 143 
 144           /* Test for positional argument.  */
 145           if (*cp >= '0' && *cp <= '9')
 146             {
 147               const CHAR_T *np;
 148 
 149               for (np = cp; *np >= '0' && *np <= '9'; np++)
 150                 ;
 151               if (*np == '$')
 152                 {
 153                   size_t n = 0;
 154 
 155                   for (np = cp; *np >= '0' && *np <= '9'; np++)
 156                     n = xsum (xtimes (n, 10), *np - '0');
 157                   if (n == 0)
 158                     /* Positional argument 0.  */
 159                     goto error;
 160                   if (size_overflow_p (n))
 161                     /* n too large, would lead to out of memory later.  */
 162                     goto error;
 163                   arg_index = n - 1;
 164                   cp = np + 1;
 165                 }
 166             }
 167 
 168           /* Read the flags.  */
 169           for (;;)
 170             {
 171               if (*cp == '\'')
 172                 {
 173                   dp->flags |= FLAG_GROUP;
 174                   cp++;
 175                 }
 176               else if (*cp == '-')
 177                 {
 178                   dp->flags |= FLAG_LEFT;
 179                   cp++;
 180                 }
 181               else if (*cp == '+')
 182                 {
 183                   dp->flags |= FLAG_SHOWSIGN;
 184                   cp++;
 185                 }
 186               else if (*cp == ' ')
 187                 {
 188                   dp->flags |= FLAG_SPACE;
 189                   cp++;
 190                 }
 191               else if (*cp == '#')
 192                 {
 193                   dp->flags |= FLAG_ALT;
 194                   cp++;
 195                 }
 196               else if (*cp == '0')
 197                 {
 198                   dp->flags |= FLAG_ZERO;
 199                   cp++;
 200                 }
 201 #if __GLIBC__ >= 2 && !defined __UCLIBC__
 202               else if (*cp == 'I')
 203                 {
 204                   dp->flags |= FLAG_LOCALIZED;
 205                   cp++;
 206                 }
 207 #endif
 208               else
 209                 break;
 210             }
 211 
 212           /* Parse the field width.  */
 213           if (*cp == '*')
 214             {
 215               dp->width_start = cp;
 216               cp++;
 217               dp->width_end = cp;
 218               if (max_width_length < 1)
 219                 max_width_length = 1;
 220 
 221               /* Test for positional argument.  */
 222               if (*cp >= '0' && *cp <= '9')
 223                 {
 224                   const CHAR_T *np;
 225 
 226                   for (np = cp; *np >= '0' && *np <= '9'; np++)
 227                     ;
 228                   if (*np == '$')
 229                     {
 230                       size_t n = 0;
 231 
 232                       for (np = cp; *np >= '0' && *np <= '9'; np++)
 233                         n = xsum (xtimes (n, 10), *np - '0');
 234                       if (n == 0)
 235                         /* Positional argument 0.  */
 236                         goto error;
 237                       if (size_overflow_p (n))
 238                         /* n too large, would lead to out of memory later.  */
 239                         goto error;
 240                       dp->width_arg_index = n - 1;
 241                       cp = np + 1;
 242                     }
 243                 }
 244               if (dp->width_arg_index == ARG_NONE)
 245                 {
 246                   dp->width_arg_index = arg_posn++;
 247                   if (dp->width_arg_index == ARG_NONE)
 248                     /* arg_posn wrapped around.  */
 249                     goto error;
 250                 }
 251               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
 252             }
 253           else if (*cp >= '0' && *cp <= '9')
 254             {
 255               size_t width_length;
 256 
 257               dp->width_start = cp;
 258               for (; *cp >= '0' && *cp <= '9'; cp++)
 259                 ;
 260               dp->width_end = cp;
 261               width_length = dp->width_end - dp->width_start;
 262               if (max_width_length < width_length)
 263                 max_width_length = width_length;
 264             }
 265 
 266           /* Parse the precision.  */
 267           if (*cp == '.')
 268             {
 269               cp++;
 270               if (*cp == '*')
 271                 {
 272                   dp->precision_start = cp - 1;
 273                   cp++;
 274                   dp->precision_end = cp;
 275                   if (max_precision_length < 2)
 276                     max_precision_length = 2;
 277 
 278                   /* Test for positional argument.  */
 279                   if (*cp >= '0' && *cp <= '9')
 280                     {
 281                       const CHAR_T *np;
 282 
 283                       for (np = cp; *np >= '0' && *np <= '9'; np++)
 284                         ;
 285                       if (*np == '$')
 286                         {
 287                           size_t n = 0;
 288 
 289                           for (np = cp; *np >= '0' && *np <= '9'; np++)
 290                             n = xsum (xtimes (n, 10), *np - '0');
 291                           if (n == 0)
 292                             /* Positional argument 0.  */
 293                             goto error;
 294                           if (size_overflow_p (n))
 295                             /* n too large, would lead to out of memory
 296                                later.  */
 297                             goto error;
 298                           dp->precision_arg_index = n - 1;
 299                           cp = np + 1;
 300                         }
 301                     }
 302                   if (dp->precision_arg_index == ARG_NONE)
 303                     {
 304                       dp->precision_arg_index = arg_posn++;
 305                       if (dp->precision_arg_index == ARG_NONE)
 306                         /* arg_posn wrapped around.  */
 307                         goto error;
 308                     }
 309                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
 310                 }
 311               else
 312                 {
 313                   size_t precision_length;
 314 
 315                   dp->precision_start = cp - 1;
 316                   for (; *cp >= '0' && *cp <= '9'; cp++)
 317                     ;
 318                   dp->precision_end = cp;
 319                   precision_length = dp->precision_end - dp->precision_start;
 320                   if (max_precision_length < precision_length)
 321                     max_precision_length = precision_length;
 322                 }
 323             }
 324 
 325           {
 326             arg_type type;
 327 
 328             /* Parse argument type/size specifiers.  */
 329             {
 330               int flags = 0;
 331 
 332               for (;;)
 333                 {
 334                   if (*cp == 'h')
 335                     {
 336                       flags |= (1 << (flags & 1));
 337                       cp++;
 338                     }
 339                   else if (*cp == 'L')
 340                     {
 341                       flags |= 4;
 342                       cp++;
 343                     }
 344                   else if (*cp == 'l')
 345                     {
 346                       flags += 8;
 347                       cp++;
 348                     }
 349                   else if (*cp == 'j')
 350                     {
 351                       if (sizeof (intmax_t) > sizeof (long))
 352                         {
 353                           /* intmax_t = long long */
 354                           flags += 16;
 355                         }
 356                       else if (sizeof (intmax_t) > sizeof (int))
 357                         {
 358                           /* intmax_t = long */
 359                           flags += 8;
 360                         }
 361                       cp++;
 362                     }
 363                   else if (*cp == 'z' || *cp == 'Z')
 364                     {
 365                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
 366                          because the warning facility in gcc-2.95.2 understands
 367                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
 368                       if (sizeof (size_t) > sizeof (long))
 369                         {
 370                           /* size_t = long long */
 371                           flags += 16;
 372                         }
 373                       else if (sizeof (size_t) > sizeof (int))
 374                         {
 375                           /* size_t = long */
 376                           flags += 8;
 377                         }
 378                       cp++;
 379                     }
 380                   else if (*cp == 't')
 381                     {
 382                       if (sizeof (ptrdiff_t) > sizeof (long))
 383                         {
 384                           /* ptrdiff_t = long long */
 385                           flags += 16;
 386                         }
 387                       else if (sizeof (ptrdiff_t) > sizeof (int))
 388                         {
 389                           /* ptrdiff_t = long */
 390                           flags += 8;
 391                         }
 392                       cp++;
 393                     }
 394 #if defined __APPLE__ && defined __MACH__
 395                   /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
 396                      We cannot change it to "lld" because PRIdMAX must also
 397                      be understood by the system's printf routines.  */
 398                   else if (*cp == 'q')
 399                     {
 400                       if (64 / 8 > sizeof (long))
 401                         {
 402                           /* int64_t = long long */
 403                           flags += 16;
 404                         }
 405                       else
 406                         {
 407                           /* int64_t = long */
 408                           flags += 8;
 409                         }
 410                       cp++;
 411                     }
 412 #endif
 413 #if defined _WIN32 && ! defined __CYGWIN__
 414                   /* On native Windows, PRIdMAX is defined as "I64d".
 415                      We cannot change it to "lld" because PRIdMAX must also
 416                      be understood by the system's printf routines.  */
 417                   else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
 418                     {
 419                       if (64 / 8 > sizeof (long))
 420                         {
 421                           /* __int64 = long long */
 422                           flags += 16;
 423                         }
 424                       else
 425                         {
 426                           /* __int64 = long */
 427                           flags += 8;
 428                         }
 429                       cp += 3;
 430                     }
 431 #endif
 432                   else
 433                     break;
 434                 }
 435 
 436               /* Read the conversion character.  */
 437               c = *cp++;
 438               switch (c)
 439                 {
 440                 case 'd': case 'i':
 441                   /* If 'long long' is larger than 'long':  */
 442                   if (flags >= 16 || (flags & 4))
 443                     type = TYPE_LONGLONGINT;
 444                   else
 445                   /* If 'long long' is the same as 'long', we parse "lld" into
 446                      TYPE_LONGINT.  */
 447                   if (flags >= 8)
 448                     type = TYPE_LONGINT;
 449                   else if (flags & 2)
 450                     type = TYPE_SCHAR;
 451                   else if (flags & 1)
 452                     type = TYPE_SHORT;
 453                   else
 454                     type = TYPE_INT;
 455                   break;
 456                 case 'o': case 'u': case 'x': case 'X':
 457                   /* If 'unsigned long long' is larger than 'unsigned long':  */
 458                   if (flags >= 16 || (flags & 4))
 459                     type = TYPE_ULONGLONGINT;
 460                   else
 461                   /* If 'unsigned long long' is the same as 'unsigned long', we
 462                      parse "llu" into TYPE_ULONGINT.  */
 463                   if (flags >= 8)
 464                     type = TYPE_ULONGINT;
 465                   else if (flags & 2)
 466                     type = TYPE_UCHAR;
 467                   else if (flags & 1)
 468                     type = TYPE_USHORT;
 469                   else
 470                     type = TYPE_UINT;
 471                   break;
 472                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
 473                 case 'a': case 'A':
 474                   if (flags >= 16 || (flags & 4))
 475                     type = TYPE_LONGDOUBLE;
 476                   else
 477                     type = TYPE_DOUBLE;
 478                   break;
 479                 case 'c':
 480                   if (flags >= 8)
 481 #if HAVE_WINT_T
 482                     type = TYPE_WIDE_CHAR;
 483 #else
 484                     goto error;
 485 #endif
 486                   else
 487                     type = TYPE_CHAR;
 488                   break;
 489 #if HAVE_WINT_T
 490                 case 'C':
 491                   type = TYPE_WIDE_CHAR;
 492                   c = 'c';
 493                   break;
 494 #endif
 495                 case 's':
 496                   if (flags >= 8)
 497 #if HAVE_WCHAR_T
 498                     type = TYPE_WIDE_STRING;
 499 #else
 500                     goto error;
 501 #endif
 502                   else
 503                     type = TYPE_STRING;
 504                   break;
 505 #if HAVE_WCHAR_T
 506                 case 'S':
 507                   type = TYPE_WIDE_STRING;
 508                   c = 's';
 509                   break;
 510 #endif
 511                 case 'p':
 512                   type = TYPE_POINTER;
 513                   break;
 514                 case 'n':
 515                   /* If 'long long' is larger than 'long':  */
 516                   if (flags >= 16 || (flags & 4))
 517                     type = TYPE_COUNT_LONGLONGINT_POINTER;
 518                   else
 519                   /* If 'long long' is the same as 'long', we parse "lln" into
 520                      TYPE_COUNT_LONGINT_POINTER.  */
 521                   if (flags >= 8)
 522                     type = TYPE_COUNT_LONGINT_POINTER;
 523                   else if (flags & 2)
 524                     type = TYPE_COUNT_SCHAR_POINTER;
 525                   else if (flags & 1)
 526                     type = TYPE_COUNT_SHORT_POINTER;
 527                   else
 528                     type = TYPE_COUNT_INT_POINTER;
 529                   break;
 530 #if ENABLE_UNISTDIO
 531                 /* The unistdio extensions.  */
 532                 case 'U':
 533                   if (flags >= 16)
 534                     type = TYPE_U32_STRING;
 535                   else if (flags >= 8)
 536                     type = TYPE_U16_STRING;
 537                   else
 538                     type = TYPE_U8_STRING;
 539                   break;
 540 #endif
 541                 case '%':
 542                   type = TYPE_NONE;
 543                   break;
 544                 default:
 545                   /* Unknown conversion character.  */
 546                   goto error;
 547                 }
 548             }
 549 
 550             if (type != TYPE_NONE)
 551               {
 552                 dp->arg_index = arg_index;
 553                 if (dp->arg_index == ARG_NONE)
 554                   {
 555                     dp->arg_index = arg_posn++;
 556                     if (dp->arg_index == ARG_NONE)
 557                       /* arg_posn wrapped around.  */
 558                       goto error;
 559                   }
 560                 REGISTER_ARG (dp->arg_index, type);
 561               }
 562             dp->conversion = c;
 563             dp->dir_end = cp;
 564           }
 565 
 566           d->count++;
 567           if (d->count >= d_allocated)
 568             {
 569               size_t memory_size;
 570               DIRECTIVE *memory;
 571 
 572               d_allocated = xtimes (d_allocated, 2);
 573               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
 574               if (size_overflow_p (memory_size))
 575                 /* Overflow, would lead to out of memory.  */
 576                 goto out_of_memory;
 577               memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
 578                                       ? realloc (d->dir, memory_size)
 579                                       : malloc (memory_size));
 580               if (memory == NULL)
 581                 /* Out of memory.  */
 582                 goto out_of_memory;
 583               if (d->dir == d->direct_alloc_dir)
 584                 memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
 585               d->dir = memory;
 586             }
 587         }
 588 #if CHAR_T_ONLY_ASCII
 589       else if (!c_isascii (c))
 590         {
 591           /* Non-ASCII character.  Not supported.  */
 592           goto error;
 593         }
 594 #endif
 595     }
 596   d->dir[d->count].dir_start = cp;
 597 
 598   d->max_width_length = max_width_length;
 599   d->max_precision_length = max_precision_length;
 600   return 0;
 601 
 602 error:
 603   if (a->arg != a->direct_alloc_arg)
 604     free (a->arg);
 605   if (d->dir != d->direct_alloc_dir)
 606     free (d->dir);
 607   errno = EINVAL;
 608   return -1;
 609 
 610 out_of_memory:
 611   if (a->arg != a->direct_alloc_arg)
 612     free (a->arg);
 613   if (d->dir != d->direct_alloc_dir)
 614     free (d->dir);
 615   errno = ENOMEM;
 616   return -1;
 617 }
 618 
 619 #undef PRINTF_PARSE
 620 #undef DIRECTIVES
 621 #undef DIRECTIVE
 622 #undef CHAR_T_ONLY_ASCII
 623 #undef CHAR_T

/* [previous][next][first][last][top][bottom][index][help] */