Back to index

tetex-bin  3.0
printf-parse.c
Go to the documentation of this file.
00001 /* Formatted output to strings.
00002    Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify it
00005    under the terms of the GNU Library General Public License as published
00006    by the Free Software Foundation; either version 2, or (at your option)
00007    any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public
00015    License along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00017    USA.  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022 
00023 /* Specification.  */
00024 #if WIDE_CHAR_VERSION
00025 # include "wprintf-parse.h"
00026 #else
00027 # include "printf-parse.h"
00028 #endif
00029 
00030 /* Get size_t, NULL.  */
00031 #include <stddef.h>
00032 
00033 /* Get intmax_t.  */
00034 #if HAVE_STDINT_H_WITH_UINTMAX
00035 # include <stdint.h>
00036 #endif
00037 #if HAVE_INTTYPES_H_WITH_UINTMAX
00038 # include <inttypes.h>
00039 #endif
00040 
00041 /* malloc(), realloc(), free().  */
00042 #include <stdlib.h>
00043 
00044 /* Checked size_t computations.  */
00045 #include "xsize.h"
00046 
00047 #if WIDE_CHAR_VERSION
00048 # define PRINTF_PARSE wprintf_parse
00049 # define CHAR_T wchar_t
00050 # define DIRECTIVE wchar_t_directive
00051 # define DIRECTIVES wchar_t_directives
00052 #else
00053 # define PRINTF_PARSE printf_parse
00054 # define CHAR_T char
00055 # define DIRECTIVE char_directive
00056 # define DIRECTIVES char_directives
00057 #endif
00058 
00059 #ifdef STATIC
00060 STATIC
00061 #endif
00062 int
00063 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
00064 {
00065   const CHAR_T *cp = format;              /* pointer into format */
00066   size_t arg_posn = 0;             /* number of regular arguments consumed */
00067   size_t d_allocated;                     /* allocated elements of d->dir */
00068   size_t a_allocated;                     /* allocated elements of a->arg */
00069   size_t max_width_length = 0;
00070   size_t max_precision_length = 0;
00071 
00072   d->count = 0;
00073   d_allocated = 1;
00074   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
00075   if (d->dir == NULL)
00076     /* Out of memory.  */
00077     return -1;
00078 
00079   a->count = 0;
00080   a_allocated = 0;
00081   a->arg = NULL;
00082 
00083 #define REGISTER_ARG(_index_,_type_) \
00084   {                                                            \
00085     size_t n = (_index_);                                      \
00086     if (n >= a_allocated)                                      \
00087       {                                                               \
00088        size_t memory_size;                                     \
00089        argument *memory;                                       \
00090                                                                \
00091        a_allocated = xtimes (a_allocated, 2);                         \
00092        if (a_allocated <= n)                                          \
00093          a_allocated = xsum (n, 1);                                   \
00094        memory_size = xtimes (a_allocated, sizeof (argument));         \
00095        if (size_overflow_p (memory_size))                      \
00096          /* Overflow, would lead to out of memory.  */                \
00097          goto error;                                           \
00098        memory = (a->arg                                        \
00099                 ? realloc (a->arg, memory_size)                \
00100                 : malloc (memory_size));                       \
00101        if (memory == NULL)                                     \
00102          /* Out of memory.  */                                        \
00103          goto error;                                           \
00104        a->arg = memory;                                        \
00105       }                                                               \
00106     while (a->count <= n)                                      \
00107       a->arg[a->count++].type = TYPE_NONE;                            \
00108     if (a->arg[n].type == TYPE_NONE)                                  \
00109       a->arg[n].type = (_type_);                               \
00110     else if (a->arg[n].type != (_type_))                       \
00111       /* Ambiguous type for positional argument.  */                  \
00112       goto error;                                              \
00113   }
00114 
00115   while (*cp != '\0')
00116     {
00117       CHAR_T c = *cp++;
00118       if (c == '%')
00119        {
00120          size_t arg_index = ARG_NONE;
00121          DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
00122 
00123          /* Initialize the next directive.  */
00124          dp->dir_start = cp - 1;
00125          dp->flags = 0;
00126          dp->width_start = NULL;
00127          dp->width_end = NULL;
00128          dp->width_arg_index = ARG_NONE;
00129          dp->precision_start = NULL;
00130          dp->precision_end = NULL;
00131          dp->precision_arg_index = ARG_NONE;
00132          dp->arg_index = ARG_NONE;
00133 
00134          /* Test for positional argument.  */
00135          if (*cp >= '0' && *cp <= '9')
00136            {
00137              const CHAR_T *np;
00138 
00139              for (np = cp; *np >= '0' && *np <= '9'; np++)
00140               ;
00141              if (*np == '$')
00142               {
00143                 size_t n = 0;
00144 
00145                 for (np = cp; *np >= '0' && *np <= '9'; np++)
00146                   n = xsum (xtimes (n, 10), *np - '0');
00147                 if (n == 0)
00148                   /* Positional argument 0.  */
00149                   goto error;
00150                 if (size_overflow_p (n))
00151                   /* n too large, would lead to out of memory later.  */
00152                   goto error;
00153                 arg_index = n - 1;
00154                 cp = np + 1;
00155               }
00156            }
00157 
00158          /* Read the flags.  */
00159          for (;;)
00160            {
00161              if (*cp == '\'')
00162               {
00163                 dp->flags |= FLAG_GROUP;
00164                 cp++;
00165               }
00166              else if (*cp == '-')
00167               {
00168                 dp->flags |= FLAG_LEFT;
00169                 cp++;
00170               }
00171              else if (*cp == '+')
00172               {
00173                 dp->flags |= FLAG_SHOWSIGN;
00174                 cp++;
00175               }
00176              else if (*cp == ' ')
00177               {
00178                 dp->flags |= FLAG_SPACE;
00179                 cp++;
00180               }
00181              else if (*cp == '#')
00182               {
00183                 dp->flags |= FLAG_ALT;
00184                 cp++;
00185               }
00186              else if (*cp == '0')
00187               {
00188                 dp->flags |= FLAG_ZERO;
00189                 cp++;
00190               }
00191              else
00192               break;
00193            }
00194 
00195          /* Parse the field width.  */
00196          if (*cp == '*')
00197            {
00198              dp->width_start = cp;
00199              cp++;
00200              dp->width_end = cp;
00201              if (max_width_length < 1)
00202               max_width_length = 1;
00203 
00204              /* Test for positional argument.  */
00205              if (*cp >= '0' && *cp <= '9')
00206               {
00207                 const CHAR_T *np;
00208 
00209                 for (np = cp; *np >= '0' && *np <= '9'; np++)
00210                   ;
00211                 if (*np == '$')
00212                   {
00213                     size_t n = 0;
00214 
00215                     for (np = cp; *np >= '0' && *np <= '9'; np++)
00216                      n = xsum (xtimes (n, 10), *np - '0');
00217                     if (n == 0)
00218                      /* Positional argument 0.  */
00219                      goto error;
00220                     if (size_overflow_p (n))
00221                      /* n too large, would lead to out of memory later.  */
00222                      goto error;
00223                     dp->width_arg_index = n - 1;
00224                     cp = np + 1;
00225                   }
00226               }
00227              if (dp->width_arg_index == ARG_NONE)
00228               {
00229                 dp->width_arg_index = arg_posn++;
00230                 if (dp->width_arg_index == ARG_NONE)
00231                   /* arg_posn wrapped around.  */
00232                   goto error;
00233               }
00234              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
00235            }
00236          else if (*cp >= '0' && *cp <= '9')
00237            {
00238              size_t width_length;
00239 
00240              dp->width_start = cp;
00241              for (; *cp >= '0' && *cp <= '9'; cp++)
00242               ;
00243              dp->width_end = cp;
00244              width_length = dp->width_end - dp->width_start;
00245              if (max_width_length < width_length)
00246               max_width_length = width_length;
00247            }
00248 
00249          /* Parse the precision.  */
00250          if (*cp == '.')
00251            {
00252              cp++;
00253              if (*cp == '*')
00254               {
00255                 dp->precision_start = cp - 1;
00256                 cp++;
00257                 dp->precision_end = cp;
00258                 if (max_precision_length < 2)
00259                   max_precision_length = 2;
00260 
00261                 /* Test for positional argument.  */
00262                 if (*cp >= '0' && *cp <= '9')
00263                   {
00264                     const CHAR_T *np;
00265 
00266                     for (np = cp; *np >= '0' && *np <= '9'; np++)
00267                      ;
00268                     if (*np == '$')
00269                      {
00270                        size_t n = 0;
00271 
00272                        for (np = cp; *np >= '0' && *np <= '9'; np++)
00273                          n = xsum (xtimes (n, 10), *np - '0');
00274                        if (n == 0)
00275                          /* Positional argument 0.  */
00276                          goto error;
00277                        if (size_overflow_p (n))
00278                          /* n too large, would lead to out of memory
00279                             later.  */
00280                          goto error;
00281                        dp->precision_arg_index = n - 1;
00282                        cp = np + 1;
00283                      }
00284                   }
00285                 if (dp->precision_arg_index == ARG_NONE)
00286                   {
00287                     dp->precision_arg_index = arg_posn++;
00288                     if (dp->precision_arg_index == ARG_NONE)
00289                      /* arg_posn wrapped around.  */
00290                      goto error;
00291                   }
00292                 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
00293               }
00294              else
00295               {
00296                 size_t precision_length;
00297 
00298                 dp->precision_start = cp - 1;
00299                 for (; *cp >= '0' && *cp <= '9'; cp++)
00300                   ;
00301                 dp->precision_end = cp;
00302                 precision_length = dp->precision_end - dp->precision_start;
00303                 if (max_precision_length < precision_length)
00304                   max_precision_length = precision_length;
00305               }
00306            }
00307 
00308          {
00309            arg_type type;
00310 
00311            /* Parse argument type/size specifiers.  */
00312            {
00313              int flags = 0;
00314 
00315              for (;;)
00316               {
00317                 if (*cp == 'h')
00318                   {
00319                     flags |= (1 << (flags & 1));
00320                     cp++;
00321                   }
00322                 else if (*cp == 'L')
00323                   {
00324                     flags |= 4;
00325                     cp++;
00326                   }
00327                 else if (*cp == 'l')
00328                   {
00329                     flags += 8;
00330                     cp++;
00331                   }
00332 #ifdef HAVE_INTMAX_T
00333                 else if (*cp == 'j')
00334                   {
00335                     if (sizeof (intmax_t) > sizeof (long))
00336                      {
00337                        /* intmax_t = long long */
00338                        flags += 16;
00339                      }
00340                     else if (sizeof (intmax_t) > sizeof (int))
00341                      {
00342                        /* intmax_t = long */
00343                        flags += 8;
00344                      }
00345                     cp++;
00346                   }
00347 #endif
00348                 else if (*cp == 'z' || *cp == 'Z')
00349                   {
00350                     /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
00351                       because the warning facility in gcc-2.95.2 understands
00352                       only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
00353                     if (sizeof (size_t) > sizeof (long))
00354                      {
00355                        /* size_t = long long */
00356                        flags += 16;
00357                      }
00358                     else if (sizeof (size_t) > sizeof (int))
00359                      {
00360                        /* size_t = long */
00361                        flags += 8;
00362                      }
00363                     cp++;
00364                   }
00365                 else if (*cp == 't')
00366                   {
00367                     if (sizeof (ptrdiff_t) > sizeof (long))
00368                      {
00369                        /* ptrdiff_t = long long */
00370                        flags += 16;
00371                      }
00372                     else if (sizeof (ptrdiff_t) > sizeof (int))
00373                      {
00374                        /* ptrdiff_t = long */
00375                        flags += 8;
00376                      }
00377                     cp++;
00378                   }
00379                 else
00380                   break;
00381               }
00382 
00383              /* Read the conversion character.  */
00384              c = *cp++;
00385              switch (c)
00386               {
00387               case 'd': case 'i':
00388 #ifdef HAVE_LONG_LONG
00389                 if (flags >= 16 || (flags & 4))
00390                   type = TYPE_LONGLONGINT;
00391                 else
00392 #endif
00393                 if (flags >= 8)
00394                   type = TYPE_LONGINT;
00395                 else if (flags & 2)
00396                   type = TYPE_SCHAR;
00397                 else if (flags & 1)
00398                   type = TYPE_SHORT;
00399                 else
00400                   type = TYPE_INT;
00401                 break;
00402               case 'o': case 'u': case 'x': case 'X':
00403 #ifdef HAVE_LONG_LONG
00404                 if (flags >= 16 || (flags & 4))
00405                   type = TYPE_ULONGLONGINT;
00406                 else
00407 #endif
00408                 if (flags >= 8)
00409                   type = TYPE_ULONGINT;
00410                 else if (flags & 2)
00411                   type = TYPE_UCHAR;
00412                 else if (flags & 1)
00413                   type = TYPE_USHORT;
00414                 else
00415                   type = TYPE_UINT;
00416                 break;
00417               case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
00418               case 'a': case 'A':
00419 #ifdef HAVE_LONG_DOUBLE
00420                 if (flags >= 16 || (flags & 4))
00421                   type = TYPE_LONGDOUBLE;
00422                 else
00423 #endif
00424                 type = TYPE_DOUBLE;
00425                 break;
00426               case 'c':
00427                 if (flags >= 8)
00428 #ifdef HAVE_WINT_T
00429                   type = TYPE_WIDE_CHAR;
00430 #else
00431                   goto error;
00432 #endif
00433                 else
00434                   type = TYPE_CHAR;
00435                 break;
00436 #ifdef HAVE_WINT_T
00437               case 'C':
00438                 type = TYPE_WIDE_CHAR;
00439                 c = 'c';
00440                 break;
00441 #endif
00442               case 's':
00443                 if (flags >= 8)
00444 #ifdef HAVE_WCHAR_T
00445                   type = TYPE_WIDE_STRING;
00446 #else
00447                   goto error;
00448 #endif
00449                 else
00450                   type = TYPE_STRING;
00451                 break;
00452 #ifdef HAVE_WCHAR_T
00453               case 'S':
00454                 type = TYPE_WIDE_STRING;
00455                 c = 's';
00456                 break;
00457 #endif
00458               case 'p':
00459                 type = TYPE_POINTER;
00460                 break;
00461               case 'n':
00462 #ifdef HAVE_LONG_LONG
00463                 if (flags >= 16 || (flags & 4))
00464                   type = TYPE_COUNT_LONGLONGINT_POINTER;
00465                 else
00466 #endif
00467                 if (flags >= 8)
00468                   type = TYPE_COUNT_LONGINT_POINTER;
00469                 else if (flags & 2)
00470                   type = TYPE_COUNT_SCHAR_POINTER;
00471                 else if (flags & 1)
00472                   type = TYPE_COUNT_SHORT_POINTER;
00473                 else
00474                   type = TYPE_COUNT_INT_POINTER;
00475                 break;
00476               case '%':
00477                 type = TYPE_NONE;
00478                 break;
00479               default:
00480                 /* Unknown conversion character.  */
00481                 goto error;
00482               }
00483            }
00484 
00485            if (type != TYPE_NONE)
00486              {
00487               dp->arg_index = arg_index;
00488               if (dp->arg_index == ARG_NONE)
00489                 {
00490                   dp->arg_index = arg_posn++;
00491                   if (dp->arg_index == ARG_NONE)
00492                     /* arg_posn wrapped around.  */
00493                     goto error;
00494                 }
00495               REGISTER_ARG (dp->arg_index, type);
00496              }
00497            dp->conversion = c;
00498            dp->dir_end = cp;
00499          }
00500 
00501          d->count++;
00502          if (d->count >= d_allocated)
00503            {
00504              size_t memory_size;
00505              DIRECTIVE *memory;
00506 
00507              d_allocated = xtimes (d_allocated, 2);
00508              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
00509              if (size_overflow_p (memory_size))
00510               /* Overflow, would lead to out of memory.  */
00511               goto error;
00512              memory = realloc (d->dir, memory_size);
00513              if (memory == NULL)
00514               /* Out of memory.  */
00515               goto error;
00516              d->dir = memory;
00517            }
00518        }
00519     }
00520   d->dir[d->count].dir_start = cp;
00521 
00522   d->max_width_length = max_width_length;
00523   d->max_precision_length = max_precision_length;
00524   return 0;
00525 
00526 error:
00527   if (a->arg)
00528     free (a->arg);
00529   if (d->dir)
00530     free (d->dir);
00531   return -1;
00532 }
00533 
00534 #undef DIRECTIVES
00535 #undef DIRECTIVE
00536 #undef CHAR_T
00537 #undef PRINTF_PARSE