printf-parse.c

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

Generated on Wed Jul 12 17:53:19 2006 for WvStreams by  doxygen 1.4.7