Back to index

nagios-plugins  1.4.16
printf-parse.c
Go to the documentation of this file.
00001 /* Formatted output to strings.
00002    Copyright (C) 1999-2000, 2002-2003, 2006-2010 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 General Public License as published by
00006    the Free Software Foundation; either version 3, 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 General Public License for more details.
00013 
00014    You should have received a copy of the GNU 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 /* This file can be parametrized with the following macros:
00019      CHAR_T             The element type of the format string.
00020      CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
00021                         in the format string are ASCII.
00022      DIRECTIVE          Structure denoting a format directive.
00023                         Depends on CHAR_T.
00024      DIRECTIVES         Structure denoting the set of format directives of a
00025                         format string.  Depends on CHAR_T.
00026      PRINTF_PARSE       Function that parses a format string.
00027                         Depends on CHAR_T.
00028      STATIC             Set to 'static' to declare the function static.
00029      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
00030 
00031 #ifndef PRINTF_PARSE
00032 # include <config.h>
00033 #endif
00034 
00035 /* Specification.  */
00036 #ifndef PRINTF_PARSE
00037 # include "printf-parse.h"
00038 #endif
00039 
00040 /* Default parameters.  */
00041 #ifndef PRINTF_PARSE
00042 # define PRINTF_PARSE printf_parse
00043 # define CHAR_T char
00044 # define DIRECTIVE char_directive
00045 # define DIRECTIVES char_directives
00046 #endif
00047 
00048 /* Get size_t, NULL.  */
00049 #include <stddef.h>
00050 
00051 /* Get intmax_t.  */
00052 #if defined IN_LIBINTL || defined IN_LIBASPRINTF
00053 # if HAVE_STDINT_H_WITH_UINTMAX
00054 #  include <stdint.h>
00055 # endif
00056 # if HAVE_INTTYPES_H_WITH_UINTMAX
00057 #  include <inttypes.h>
00058 # endif
00059 #else
00060 # include <stdint.h>
00061 #endif
00062 
00063 /* malloc(), realloc(), free().  */
00064 #include <stdlib.h>
00065 
00066 /* errno.  */
00067 #include <errno.h>
00068 
00069 /* Checked size_t computations.  */
00070 #include "xsize.h"
00071 
00072 #if CHAR_T_ONLY_ASCII
00073 /* c_isascii().  */
00074 # include "c-ctype.h"
00075 #endif
00076 
00077 #ifdef STATIC
00078 STATIC
00079 #endif
00080 int
00081 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
00082 {
00083   const CHAR_T *cp = format;            /* pointer into format */
00084   size_t arg_posn = 0;          /* number of regular arguments consumed */
00085   size_t d_allocated;                   /* allocated elements of d->dir */
00086   size_t a_allocated;                   /* allocated elements of a->arg */
00087   size_t max_width_length = 0;
00088   size_t max_precision_length = 0;
00089 
00090   d->count = 0;
00091   d_allocated = 1;
00092   d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
00093   if (d->dir == NULL)
00094     /* Out of memory.  */
00095     goto out_of_memory_1;
00096 
00097   a->count = 0;
00098   a_allocated = 0;
00099   a->arg = NULL;
00100 
00101 #define REGISTER_ARG(_index_,_type_) \
00102   {                                                                     \
00103     size_t n = (_index_);                                               \
00104     if (n >= a_allocated)                                               \
00105       {                                                                 \
00106         size_t memory_size;                                             \
00107         argument *memory;                                               \
00108                                                                         \
00109         a_allocated = xtimes (a_allocated, 2);                          \
00110         if (a_allocated <= n)                                           \
00111           a_allocated = xsum (n, 1);                                    \
00112         memory_size = xtimes (a_allocated, sizeof (argument));          \
00113         if (size_overflow_p (memory_size))                              \
00114           /* Overflow, would lead to out of memory.  */                 \
00115           goto out_of_memory;                                           \
00116         memory = (argument *) (a->arg                                   \
00117                                ? realloc (a->arg, memory_size)          \
00118                                : malloc (memory_size));                 \
00119         if (memory == NULL)                                             \
00120           /* Out of memory.  */                                         \
00121           goto out_of_memory;                                           \
00122         a->arg = memory;                                                \
00123       }                                                                 \
00124     while (a->count <= n)                                               \
00125       a->arg[a->count++].type = TYPE_NONE;                              \
00126     if (a->arg[n].type == TYPE_NONE)                                    \
00127       a->arg[n].type = (_type_);                                        \
00128     else if (a->arg[n].type != (_type_))                                \
00129       /* Ambiguous type for positional argument.  */                    \
00130       goto error;                                                       \
00131   }
00132 
00133   while (*cp != '\0')
00134     {
00135       CHAR_T c = *cp++;
00136       if (c == '%')
00137         {
00138           size_t arg_index = ARG_NONE;
00139           DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
00140 
00141           /* Initialize the next directive.  */
00142           dp->dir_start = cp - 1;
00143           dp->flags = 0;
00144           dp->width_start = NULL;
00145           dp->width_end = NULL;
00146           dp->width_arg_index = ARG_NONE;
00147           dp->precision_start = NULL;
00148           dp->precision_end = NULL;
00149           dp->precision_arg_index = ARG_NONE;
00150           dp->arg_index = ARG_NONE;
00151 
00152           /* Test for positional argument.  */
00153           if (*cp >= '0' && *cp <= '9')
00154             {
00155               const CHAR_T *np;
00156 
00157               for (np = cp; *np >= '0' && *np <= '9'; np++)
00158                 ;
00159               if (*np == '$')
00160                 {
00161                   size_t n = 0;
00162 
00163                   for (np = cp; *np >= '0' && *np <= '9'; np++)
00164                     n = xsum (xtimes (n, 10), *np - '0');
00165                   if (n == 0)
00166                     /* Positional argument 0.  */
00167                     goto error;
00168                   if (size_overflow_p (n))
00169                     /* n too large, would lead to out of memory later.  */
00170                     goto error;
00171                   arg_index = n - 1;
00172                   cp = np + 1;
00173                 }
00174             }
00175 
00176           /* Read the flags.  */
00177           for (;;)
00178             {
00179               if (*cp == '\'')
00180                 {
00181                   dp->flags |= FLAG_GROUP;
00182                   cp++;
00183                 }
00184               else if (*cp == '-')
00185                 {
00186                   dp->flags |= FLAG_LEFT;
00187                   cp++;
00188                 }
00189               else if (*cp == '+')
00190                 {
00191                   dp->flags |= FLAG_SHOWSIGN;
00192                   cp++;
00193                 }
00194               else if (*cp == ' ')
00195                 {
00196                   dp->flags |= FLAG_SPACE;
00197                   cp++;
00198                 }
00199               else if (*cp == '#')
00200                 {
00201                   dp->flags |= FLAG_ALT;
00202                   cp++;
00203                 }
00204               else if (*cp == '0')
00205                 {
00206                   dp->flags |= FLAG_ZERO;
00207                   cp++;
00208                 }
00209               else
00210                 break;
00211             }
00212 
00213           /* Parse the field width.  */
00214           if (*cp == '*')
00215             {
00216               dp->width_start = cp;
00217               cp++;
00218               dp->width_end = cp;
00219               if (max_width_length < 1)
00220                 max_width_length = 1;
00221 
00222               /* Test for positional argument.  */
00223               if (*cp >= '0' && *cp <= '9')
00224                 {
00225                   const CHAR_T *np;
00226 
00227                   for (np = cp; *np >= '0' && *np <= '9'; np++)
00228                     ;
00229                   if (*np == '$')
00230                     {
00231                       size_t n = 0;
00232 
00233                       for (np = cp; *np >= '0' && *np <= '9'; np++)
00234                         n = xsum (xtimes (n, 10), *np - '0');
00235                       if (n == 0)
00236                         /* Positional argument 0.  */
00237                         goto error;
00238                       if (size_overflow_p (n))
00239                         /* n too large, would lead to out of memory later.  */
00240                         goto error;
00241                       dp->width_arg_index = n - 1;
00242                       cp = np + 1;
00243                     }
00244                 }
00245               if (dp->width_arg_index == ARG_NONE)
00246                 {
00247                   dp->width_arg_index = arg_posn++;
00248                   if (dp->width_arg_index == ARG_NONE)
00249                     /* arg_posn wrapped around.  */
00250                     goto error;
00251                 }
00252               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
00253             }
00254           else if (*cp >= '0' && *cp <= '9')
00255             {
00256               size_t width_length;
00257 
00258               dp->width_start = cp;
00259               for (; *cp >= '0' && *cp <= '9'; cp++)
00260                 ;
00261               dp->width_end = cp;
00262               width_length = dp->width_end - dp->width_start;
00263               if (max_width_length < width_length)
00264                 max_width_length = width_length;
00265             }
00266 
00267           /* Parse the precision.  */
00268           if (*cp == '.')
00269             {
00270               cp++;
00271               if (*cp == '*')
00272                 {
00273                   dp->precision_start = cp - 1;
00274                   cp++;
00275                   dp->precision_end = cp;
00276                   if (max_precision_length < 2)
00277                     max_precision_length = 2;
00278 
00279                   /* Test for positional argument.  */
00280                   if (*cp >= '0' && *cp <= '9')
00281                     {
00282                       const CHAR_T *np;
00283 
00284                       for (np = cp; *np >= '0' && *np <= '9'; np++)
00285                         ;
00286                       if (*np == '$')
00287                         {
00288                           size_t n = 0;
00289 
00290                           for (np = cp; *np >= '0' && *np <= '9'; np++)
00291                             n = xsum (xtimes (n, 10), *np - '0');
00292                           if (n == 0)
00293                             /* Positional argument 0.  */
00294                             goto error;
00295                           if (size_overflow_p (n))
00296                             /* n too large, would lead to out of memory
00297                                later.  */
00298                             goto error;
00299                           dp->precision_arg_index = n - 1;
00300                           cp = np + 1;
00301                         }
00302                     }
00303                   if (dp->precision_arg_index == ARG_NONE)
00304                     {
00305                       dp->precision_arg_index = arg_posn++;
00306                       if (dp->precision_arg_index == ARG_NONE)
00307                         /* arg_posn wrapped around.  */
00308                         goto error;
00309                     }
00310                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
00311                 }
00312               else
00313                 {
00314                   size_t precision_length;
00315 
00316                   dp->precision_start = cp - 1;
00317                   for (; *cp >= '0' && *cp <= '9'; cp++)
00318                     ;
00319                   dp->precision_end = cp;
00320                   precision_length = dp->precision_end - dp->precision_start;
00321                   if (max_precision_length < precision_length)
00322                     max_precision_length = precision_length;
00323                 }
00324             }
00325 
00326           {
00327             arg_type type;
00328 
00329             /* Parse argument type/size specifiers.  */
00330             {
00331               int flags = 0;
00332 
00333               for (;;)
00334                 {
00335                   if (*cp == 'h')
00336                     {
00337                       flags |= (1 << (flags & 1));
00338                       cp++;
00339                     }
00340                   else if (*cp == 'L')
00341                     {
00342                       flags |= 4;
00343                       cp++;
00344                     }
00345                   else if (*cp == 'l')
00346                     {
00347                       flags += 8;
00348                       cp++;
00349                     }
00350                   else if (*cp == 'j')
00351                     {
00352                       if (sizeof (intmax_t) > sizeof (long))
00353                         {
00354                           /* intmax_t = long long */
00355                           flags += 16;
00356                         }
00357                       else if (sizeof (intmax_t) > sizeof (int))
00358                         {
00359                           /* intmax_t = long */
00360                           flags += 8;
00361                         }
00362                       cp++;
00363                     }
00364                   else if (*cp == 'z' || *cp == 'Z')
00365                     {
00366                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
00367                          because the warning facility in gcc-2.95.2 understands
00368                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
00369                       if (sizeof (size_t) > sizeof (long))
00370                         {
00371                           /* size_t = long long */
00372                           flags += 16;
00373                         }
00374                       else if (sizeof (size_t) > sizeof (int))
00375                         {
00376                           /* size_t = long */
00377                           flags += 8;
00378                         }
00379                       cp++;
00380                     }
00381                   else if (*cp == 't')
00382                     {
00383                       if (sizeof (ptrdiff_t) > sizeof (long))
00384                         {
00385                           /* ptrdiff_t = long long */
00386                           flags += 16;
00387                         }
00388                       else if (sizeof (ptrdiff_t) > sizeof (int))
00389                         {
00390                           /* ptrdiff_t = long */
00391                           flags += 8;
00392                         }
00393                       cp++;
00394                     }
00395 #if defined __APPLE__ && defined __MACH__
00396                   /* On MacOS X 10.3, PRIdMAX is defined as "qd".
00397                      We cannot change it to "lld" because PRIdMAX must also
00398                      be understood by the system's printf routines.  */
00399                   else if (*cp == 'q')
00400                     {
00401                       if (64 / 8 > sizeof (long))
00402                         {
00403                           /* int64_t = long long */
00404                           flags += 16;
00405                         }
00406                       else
00407                         {
00408                           /* int64_t = long */
00409                           flags += 8;
00410                         }
00411                       cp++;
00412                     }
00413 #endif
00414 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
00415                   /* On native Win32, PRIdMAX is defined as "I64d".
00416                      We cannot change it to "lld" because PRIdMAX must also
00417                      be understood by the system's printf routines.  */
00418                   else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
00419                     {
00420                       if (64 / 8 > sizeof (long))
00421                         {
00422                           /* __int64 = long long */
00423                           flags += 16;
00424                         }
00425                       else
00426                         {
00427                           /* __int64 = long */
00428                           flags += 8;
00429                         }
00430                       cp += 3;
00431                     }
00432 #endif
00433                   else
00434                     break;
00435                 }
00436 
00437               /* Read the conversion character.  */
00438               c = *cp++;
00439               switch (c)
00440                 {
00441                 case 'd': case 'i':
00442 #if HAVE_LONG_LONG_INT
00443                   /* If 'long long' exists and is larger than 'long':  */
00444                   if (flags >= 16 || (flags & 4))
00445                     type = TYPE_LONGLONGINT;
00446                   else
00447 #endif
00448                   /* If 'long long' exists and is the same as 'long', we parse
00449                      "lld" into TYPE_LONGINT.  */
00450                   if (flags >= 8)
00451                     type = TYPE_LONGINT;
00452                   else if (flags & 2)
00453                     type = TYPE_SCHAR;
00454                   else if (flags & 1)
00455                     type = TYPE_SHORT;
00456                   else
00457                     type = TYPE_INT;
00458                   break;
00459                 case 'o': case 'u': case 'x': case 'X':
00460 #if HAVE_LONG_LONG_INT
00461                   /* If 'long long' exists and is larger than 'long':  */
00462                   if (flags >= 16 || (flags & 4))
00463                     type = TYPE_ULONGLONGINT;
00464                   else
00465 #endif
00466                   /* If 'unsigned long long' exists and is the same as
00467                      'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
00468                   if (flags >= 8)
00469                     type = TYPE_ULONGINT;
00470                   else if (flags & 2)
00471                     type = TYPE_UCHAR;
00472                   else if (flags & 1)
00473                     type = TYPE_USHORT;
00474                   else
00475                     type = TYPE_UINT;
00476                   break;
00477                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
00478                 case 'a': case 'A':
00479                   if (flags >= 16 || (flags & 4))
00480                     type = TYPE_LONGDOUBLE;
00481                   else
00482                     type = TYPE_DOUBLE;
00483                   break;
00484                 case 'c':
00485                   if (flags >= 8)
00486 #if HAVE_WINT_T
00487                     type = TYPE_WIDE_CHAR;
00488 #else
00489                     goto error;
00490 #endif
00491                   else
00492                     type = TYPE_CHAR;
00493                   break;
00494 #if HAVE_WINT_T
00495                 case 'C':
00496                   type = TYPE_WIDE_CHAR;
00497                   c = 'c';
00498                   break;
00499 #endif
00500                 case 's':
00501                   if (flags >= 8)
00502 #if HAVE_WCHAR_T
00503                     type = TYPE_WIDE_STRING;
00504 #else
00505                     goto error;
00506 #endif
00507                   else
00508                     type = TYPE_STRING;
00509                   break;
00510 #if HAVE_WCHAR_T
00511                 case 'S':
00512                   type = TYPE_WIDE_STRING;
00513                   c = 's';
00514                   break;
00515 #endif
00516                 case 'p':
00517                   type = TYPE_POINTER;
00518                   break;
00519                 case 'n':
00520 #if HAVE_LONG_LONG_INT
00521                   /* If 'long long' exists and is larger than 'long':  */
00522                   if (flags >= 16 || (flags & 4))
00523                     type = TYPE_COUNT_LONGLONGINT_POINTER;
00524                   else
00525 #endif
00526                   /* If 'long long' exists and is the same as 'long', we parse
00527                      "lln" into TYPE_COUNT_LONGINT_POINTER.  */
00528                   if (flags >= 8)
00529                     type = TYPE_COUNT_LONGINT_POINTER;
00530                   else if (flags & 2)
00531                     type = TYPE_COUNT_SCHAR_POINTER;
00532                   else if (flags & 1)
00533                     type = TYPE_COUNT_SHORT_POINTER;
00534                   else
00535                     type = TYPE_COUNT_INT_POINTER;
00536                   break;
00537 #if ENABLE_UNISTDIO
00538                 /* The unistdio extensions.  */
00539                 case 'U':
00540                   if (flags >= 16)
00541                     type = TYPE_U32_STRING;
00542                   else if (flags >= 8)
00543                     type = TYPE_U16_STRING;
00544                   else
00545                     type = TYPE_U8_STRING;
00546                   break;
00547 #endif
00548                 case '%':
00549                   type = TYPE_NONE;
00550                   break;
00551                 default:
00552                   /* Unknown conversion character.  */
00553                   goto error;
00554                 }
00555             }
00556 
00557             if (type != TYPE_NONE)
00558               {
00559                 dp->arg_index = arg_index;
00560                 if (dp->arg_index == ARG_NONE)
00561                   {
00562                     dp->arg_index = arg_posn++;
00563                     if (dp->arg_index == ARG_NONE)
00564                       /* arg_posn wrapped around.  */
00565                       goto error;
00566                   }
00567                 REGISTER_ARG (dp->arg_index, type);
00568               }
00569             dp->conversion = c;
00570             dp->dir_end = cp;
00571           }
00572 
00573           d->count++;
00574           if (d->count >= d_allocated)
00575             {
00576               size_t memory_size;
00577               DIRECTIVE *memory;
00578 
00579               d_allocated = xtimes (d_allocated, 2);
00580               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
00581               if (size_overflow_p (memory_size))
00582                 /* Overflow, would lead to out of memory.  */
00583                 goto out_of_memory;
00584               memory = (DIRECTIVE *) realloc (d->dir, memory_size);
00585               if (memory == NULL)
00586                 /* Out of memory.  */
00587                 goto out_of_memory;
00588               d->dir = memory;
00589             }
00590         }
00591 #if CHAR_T_ONLY_ASCII
00592       else if (!c_isascii (c))
00593         {
00594           /* Non-ASCII character.  Not supported.  */
00595           goto error;
00596         }
00597 #endif
00598     }
00599   d->dir[d->count].dir_start = cp;
00600 
00601   d->max_width_length = max_width_length;
00602   d->max_precision_length = max_precision_length;
00603   return 0;
00604 
00605 error:
00606   if (a->arg)
00607     free (a->arg);
00608   if (d->dir)
00609     free (d->dir);
00610   errno = EINVAL;
00611   return -1;
00612 
00613 out_of_memory:
00614   if (a->arg)
00615     free (a->arg);
00616   if (d->dir)
00617     free (d->dir);
00618 out_of_memory_1:
00619   errno = ENOMEM;
00620   return -1;
00621 }
00622 
00623 #undef PRINTF_PARSE
00624 #undef DIRECTIVES
00625 #undef DIRECTIVE
00626 #undef CHAR_T_ONLY_ASCII
00627 #undef CHAR_T