"Fossies" - the Fresh Open Source Software Archive

Member "sitecopy-0.16.6/intl/printf-parse.c" (3 Nov 2007, 13872 Bytes) of archive /linux/www/sitecopy-0.16.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "printf-parse.c" see the Fossies "Dox" file reference documentation.

    1 /* Formatted output to strings.
    2    Copyright (C) 1999-2000, 2002-2003, 2006-2007 Free Software Foundation, Inc.
    3 
    4    This program is free software; you can redistribute it and/or modify it
    5    under the terms of the GNU Library General Public License as published
    6    by the Free Software Foundation; either version 2, or (at your option)
    7    any later version.
    8 
    9    This program 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 GNU
   12    Library General Public License for more details.
   13 
   14    You should have received a copy of the GNU Library General Public
   15    License along with this program; if not, write to the Free Software
   16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   17    USA.  */
   18 
   19 /* This file can be parametrized with the following macros:
   20      CHAR_T             The element type of the format string.
   21      CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
   22                         in the format string are ASCII.
   23      DIRECTIVE          Structure denoting a format directive.
   24                         Depends on CHAR_T.
   25      DIRECTIVES         Structure denoting the set of format directives of a
   26                         format string.  Depends on CHAR_T.
   27      PRINTF_PARSE       Function that parses a format string.
   28                         Depends on CHAR_T.
   29      STATIC             Set to 'static' to declare the function static.
   30      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
   31 
   32 #ifndef PRINTF_PARSE
   33 # include <config.h>
   34 #endif
   35 
   36 /* Specification.  */
   37 #ifndef PRINTF_PARSE
   38 # include "printf-parse.h"
   39 #endif
   40 
   41 /* Default parameters.  */
   42 #ifndef PRINTF_PARSE
   43 # define PRINTF_PARSE printf_parse
   44 # define CHAR_T char
   45 # define DIRECTIVE char_directive
   46 # define DIRECTIVES char_directives
   47 #endif
   48 
   49 /* Get size_t, NULL.  */
   50 #include <stddef.h>
   51 
   52 /* Get intmax_t.  */
   53 #if defined IN_LIBINTL || defined IN_LIBASPRINTF
   54 # if HAVE_STDINT_H_WITH_UINTMAX
   55 #  include <stdint.h>
   56 # endif
   57 # if HAVE_INTTYPES_H_WITH_UINTMAX
   58 #  include <inttypes.h>
   59 # endif
   60 #else
   61 # include <stdint.h>
   62 #endif
   63 
   64 /* malloc(), realloc(), free().  */
   65 #include <stdlib.h>
   66 
   67 /* errno.  */
   68 #include <errno.h>
   69 
   70 /* Checked size_t computations.  */
   71 #include "xsize.h"
   72 
   73 #if CHAR_T_ONLY_ASCII
   74 /* c_isascii().  */
   75 # include "c-ctype.h"
   76 #endif
   77 
   78 #ifdef STATIC
   79 STATIC
   80 #endif
   81 int
   82 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
   83 {
   84   const CHAR_T *cp = format;        /* pointer into format */
   85   size_t arg_posn = 0;      /* number of regular arguments consumed */
   86   size_t d_allocated;           /* allocated elements of d->dir */
   87   size_t a_allocated;           /* allocated elements of a->arg */
   88   size_t max_width_length = 0;
   89   size_t max_precision_length = 0;
   90 
   91   d->count = 0;
   92   d_allocated = 1;
   93   d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
   94   if (d->dir == NULL)
   95     /* Out of memory.  */
   96     goto out_of_memory_1;
   97 
   98   a->count = 0;
   99   a_allocated = 0;
  100   a->arg = NULL;
  101 
  102 #define REGISTER_ARG(_index_,_type_) \
  103   {                                 \
  104     size_t n = (_index_);                       \
  105     if (n >= a_allocated)                       \
  106       {                                 \
  107     size_t memory_size;                     \
  108     argument *memory;                       \
  109                                     \
  110     a_allocated = xtimes (a_allocated, 2);              \
  111     if (a_allocated <= n)                       \
  112       a_allocated = xsum (n, 1);                    \
  113     memory_size = xtimes (a_allocated, sizeof (argument));      \
  114     if (size_overflow_p (memory_size))              \
  115       /* Overflow, would lead to out of memory.  */         \
  116       goto out_of_memory;                       \
  117     memory = (argument *) (a->arg                   \
  118                    ? realloc (a->arg, memory_size)      \
  119                    : malloc (memory_size));         \
  120     if (memory == NULL)                     \
  121       /* Out of memory.  */                     \
  122       goto out_of_memory;                       \
  123     a->arg = memory;                        \
  124       }                                 \
  125     while (a->count <= n)                       \
  126       a->arg[a->count++].type = TYPE_NONE;              \
  127     if (a->arg[n].type == TYPE_NONE)                    \
  128       a->arg[n].type = (_type_);                    \
  129     else if (a->arg[n].type != (_type_))                \
  130       /* Ambiguous type for positional argument.  */            \
  131       goto error;                           \
  132   }
  133 
  134   while (*cp != '\0')
  135     {
  136       CHAR_T c = *cp++;
  137       if (c == '%')
  138     {
  139       size_t arg_index = ARG_NONE;
  140       DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
  141 
  142       /* Initialize the next directive.  */
  143       dp->dir_start = cp - 1;
  144       dp->flags = 0;
  145       dp->width_start = NULL;
  146       dp->width_end = NULL;
  147       dp->width_arg_index = ARG_NONE;
  148       dp->precision_start = NULL;
  149       dp->precision_end = NULL;
  150       dp->precision_arg_index = ARG_NONE;
  151       dp->arg_index = ARG_NONE;
  152 
  153       /* Test for positional argument.  */
  154       if (*cp >= '0' && *cp <= '9')
  155         {
  156           const CHAR_T *np;
  157 
  158           for (np = cp; *np >= '0' && *np <= '9'; np++)
  159         ;
  160           if (*np == '$')
  161         {
  162           size_t n = 0;
  163 
  164           for (np = cp; *np >= '0' && *np <= '9'; np++)
  165             n = xsum (xtimes (n, 10), *np - '0');
  166           if (n == 0)
  167             /* Positional argument 0.  */
  168             goto error;
  169           if (size_overflow_p (n))
  170             /* n too large, would lead to out of memory later.  */
  171             goto error;
  172           arg_index = n - 1;
  173           cp = np + 1;
  174         }
  175         }
  176 
  177       /* Read the flags.  */
  178       for (;;)
  179         {
  180           if (*cp == '\'')
  181         {
  182           dp->flags |= FLAG_GROUP;
  183           cp++;
  184         }
  185           else if (*cp == '-')
  186         {
  187           dp->flags |= FLAG_LEFT;
  188           cp++;
  189         }
  190           else if (*cp == '+')
  191         {
  192           dp->flags |= FLAG_SHOWSIGN;
  193           cp++;
  194         }
  195           else if (*cp == ' ')
  196         {
  197           dp->flags |= FLAG_SPACE;
  198           cp++;
  199         }
  200           else if (*cp == '#')
  201         {
  202           dp->flags |= FLAG_ALT;
  203           cp++;
  204         }
  205           else if (*cp == '0')
  206         {
  207           dp->flags |= FLAG_ZERO;
  208           cp++;
  209         }
  210           else
  211         break;
  212         }
  213 
  214       /* Parse the field width.  */
  215       if (*cp == '*')
  216         {
  217           dp->width_start = cp;
  218           cp++;
  219           dp->width_end = cp;
  220           if (max_width_length < 1)
  221         max_width_length = 1;
  222 
  223           /* Test for positional argument.  */
  224           if (*cp >= '0' && *cp <= '9')
  225         {
  226           const CHAR_T *np;
  227 
  228           for (np = cp; *np >= '0' && *np <= '9'; np++)
  229             ;
  230           if (*np == '$')
  231             {
  232               size_t n = 0;
  233 
  234               for (np = cp; *np >= '0' && *np <= '9'; np++)
  235             n = xsum (xtimes (n, 10), *np - '0');
  236               if (n == 0)
  237             /* Positional argument 0.  */
  238             goto error;
  239               if (size_overflow_p (n))
  240             /* n too large, would lead to out of memory later.  */
  241             goto error;
  242               dp->width_arg_index = n - 1;
  243               cp = np + 1;
  244             }
  245         }
  246           if (dp->width_arg_index == ARG_NONE)
  247         {
  248           dp->width_arg_index = arg_posn++;
  249           if (dp->width_arg_index == ARG_NONE)
  250             /* arg_posn wrapped around.  */
  251             goto error;
  252         }
  253           REGISTER_ARG (dp->width_arg_index, TYPE_INT);
  254         }
  255       else if (*cp >= '0' && *cp <= '9')
  256         {
  257           size_t width_length;
  258 
  259           dp->width_start = cp;
  260           for (; *cp >= '0' && *cp <= '9'; cp++)
  261         ;
  262           dp->width_end = cp;
  263           width_length = dp->width_end - dp->width_start;
  264           if (max_width_length < width_length)
  265         max_width_length = width_length;
  266         }
  267 
  268       /* Parse the precision.  */
  269       if (*cp == '.')
  270         {
  271           cp++;
  272           if (*cp == '*')
  273         {
  274           dp->precision_start = cp - 1;
  275           cp++;
  276           dp->precision_end = cp;
  277           if (max_precision_length < 2)
  278             max_precision_length = 2;
  279 
  280           /* Test for positional argument.  */
  281           if (*cp >= '0' && *cp <= '9')
  282             {
  283               const CHAR_T *np;
  284 
  285               for (np = cp; *np >= '0' && *np <= '9'; np++)
  286             ;
  287               if (*np == '$')
  288             {
  289               size_t n = 0;
  290 
  291               for (np = cp; *np >= '0' && *np <= '9'; np++)
  292                 n = xsum (xtimes (n, 10), *np - '0');
  293               if (n == 0)
  294                 /* Positional argument 0.  */
  295                 goto error;
  296               if (size_overflow_p (n))
  297                 /* n too large, would lead to out of memory
  298                    later.  */
  299                 goto error;
  300               dp->precision_arg_index = n - 1;
  301               cp = np + 1;
  302             }
  303             }
  304           if (dp->precision_arg_index == ARG_NONE)
  305             {
  306               dp->precision_arg_index = arg_posn++;
  307               if (dp->precision_arg_index == ARG_NONE)
  308             /* arg_posn wrapped around.  */
  309             goto error;
  310             }
  311           REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
  312         }
  313           else
  314         {
  315           size_t precision_length;
  316 
  317           dp->precision_start = cp - 1;
  318           for (; *cp >= '0' && *cp <= '9'; cp++)
  319             ;
  320           dp->precision_end = cp;
  321           precision_length = dp->precision_end - dp->precision_start;
  322           if (max_precision_length < precision_length)
  323             max_precision_length = precision_length;
  324         }
  325         }
  326 
  327       {
  328         arg_type type;
  329 
  330         /* Parse argument type/size specifiers.  */
  331         {
  332           int flags = 0;
  333 
  334           for (;;)
  335         {
  336           if (*cp == 'h')
  337             {
  338               flags |= (1 << (flags & 1));
  339               cp++;
  340             }
  341           else if (*cp == 'L')
  342             {
  343               flags |= 4;
  344               cp++;
  345             }
  346           else if (*cp == 'l')
  347             {
  348               flags += 8;
  349               cp++;
  350             }
  351           else if (*cp == 'j')
  352             {
  353               if (sizeof (intmax_t) > sizeof (long))
  354             {
  355               /* intmax_t = long long */
  356               flags += 16;
  357             }
  358               else if (sizeof (intmax_t) > sizeof (int))
  359             {
  360               /* intmax_t = long */
  361               flags += 8;
  362             }
  363               cp++;
  364             }
  365           else if (*cp == 'z' || *cp == 'Z')
  366             {
  367               /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
  368              because the warning facility in gcc-2.95.2 understands
  369              only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
  370               if (sizeof (size_t) > sizeof (long))
  371             {
  372               /* size_t = long long */
  373               flags += 16;
  374             }
  375               else if (sizeof (size_t) > sizeof (int))
  376             {
  377               /* size_t = long */
  378               flags += 8;
  379             }
  380               cp++;
  381             }
  382           else if (*cp == 't')
  383             {
  384               if (sizeof (ptrdiff_t) > sizeof (long))
  385             {
  386               /* ptrdiff_t = long long */
  387               flags += 16;
  388             }
  389               else if (sizeof (ptrdiff_t) > sizeof (int))
  390             {
  391               /* ptrdiff_t = long */
  392               flags += 8;
  393             }
  394               cp++;
  395             }
  396           else
  397             break;
  398         }
  399 
  400           /* Read the conversion character.  */
  401           c = *cp++;
  402           switch (c)
  403         {
  404         case 'd': case 'i':
  405 #if HAVE_LONG_LONG_INT
  406           /* If 'long long' exists and is larger than 'long':  */
  407           if (flags >= 16 || (flags & 4))
  408             type = TYPE_LONGLONGINT;
  409           else
  410 #endif
  411           /* If 'long long' exists and is the same as 'long', we parse
  412              "lld" into TYPE_LONGINT.  */
  413           if (flags >= 8)
  414             type = TYPE_LONGINT;
  415           else if (flags & 2)
  416             type = TYPE_SCHAR;
  417           else if (flags & 1)
  418             type = TYPE_SHORT;
  419           else
  420             type = TYPE_INT;
  421           break;
  422         case 'o': case 'u': case 'x': case 'X':
  423 #if HAVE_LONG_LONG_INT
  424           /* If 'long long' exists and is larger than 'long':  */
  425           if (flags >= 16 || (flags & 4))
  426             type = TYPE_ULONGLONGINT;
  427           else
  428 #endif
  429           /* If 'unsigned long long' exists and is the same as
  430              'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
  431           if (flags >= 8)
  432             type = TYPE_ULONGINT;
  433           else if (flags & 2)
  434             type = TYPE_UCHAR;
  435           else if (flags & 1)
  436             type = TYPE_USHORT;
  437           else
  438             type = TYPE_UINT;
  439           break;
  440         case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
  441         case 'a': case 'A':
  442           if (flags >= 16 || (flags & 4))
  443             type = TYPE_LONGDOUBLE;
  444           else
  445             type = TYPE_DOUBLE;
  446           break;
  447         case 'c':
  448           if (flags >= 8)
  449 #if HAVE_WINT_T
  450             type = TYPE_WIDE_CHAR;
  451 #else
  452             goto error;
  453 #endif
  454           else
  455             type = TYPE_CHAR;
  456           break;
  457 #if HAVE_WINT_T
  458         case 'C':
  459           type = TYPE_WIDE_CHAR;
  460           c = 'c';
  461           break;
  462 #endif
  463         case 's':
  464           if (flags >= 8)
  465 #if HAVE_WCHAR_T
  466             type = TYPE_WIDE_STRING;
  467 #else
  468             goto error;
  469 #endif
  470           else
  471             type = TYPE_STRING;
  472           break;
  473 #if HAVE_WCHAR_T
  474         case 'S':
  475           type = TYPE_WIDE_STRING;
  476           c = 's';
  477           break;
  478 #endif
  479         case 'p':
  480           type = TYPE_POINTER;
  481           break;
  482         case 'n':
  483 #if HAVE_LONG_LONG_INT
  484           /* If 'long long' exists and is larger than 'long':  */
  485           if (flags >= 16 || (flags & 4))
  486             type = TYPE_COUNT_LONGLONGINT_POINTER;
  487           else
  488 #endif
  489           /* If 'long long' exists and is the same as 'long', we parse
  490              "lln" into TYPE_COUNT_LONGINT_POINTER.  */
  491           if (flags >= 8)
  492             type = TYPE_COUNT_LONGINT_POINTER;
  493           else if (flags & 2)
  494             type = TYPE_COUNT_SCHAR_POINTER;
  495           else if (flags & 1)
  496             type = TYPE_COUNT_SHORT_POINTER;
  497           else
  498             type = TYPE_COUNT_INT_POINTER;
  499           break;
  500 #if ENABLE_UNISTDIO
  501         /* The unistdio extensions.  */
  502         case 'U':
  503           if (flags >= 16)
  504             type = TYPE_U32_STRING;
  505           else if (flags >= 8)
  506             type = TYPE_U16_STRING;
  507           else
  508             type = TYPE_U8_STRING;
  509           break;
  510 #endif
  511         case '%':
  512           type = TYPE_NONE;
  513           break;
  514         default:
  515           /* Unknown conversion character.  */
  516           goto error;
  517         }
  518         }
  519 
  520         if (type != TYPE_NONE)
  521           {
  522         dp->arg_index = arg_index;
  523         if (dp->arg_index == ARG_NONE)
  524           {
  525             dp->arg_index = arg_posn++;
  526             if (dp->arg_index == ARG_NONE)
  527               /* arg_posn wrapped around.  */
  528               goto error;
  529           }
  530         REGISTER_ARG (dp->arg_index, type);
  531           }
  532         dp->conversion = c;
  533         dp->dir_end = cp;
  534       }
  535 
  536       d->count++;
  537       if (d->count >= d_allocated)
  538         {
  539           size_t memory_size;
  540           DIRECTIVE *memory;
  541 
  542           d_allocated = xtimes (d_allocated, 2);
  543           memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
  544           if (size_overflow_p (memory_size))
  545         /* Overflow, would lead to out of memory.  */
  546         goto out_of_memory;
  547           memory = (DIRECTIVE *) realloc (d->dir, memory_size);
  548           if (memory == NULL)
  549         /* Out of memory.  */
  550         goto out_of_memory;
  551           d->dir = memory;
  552         }
  553     }
  554 #if CHAR_T_ONLY_ASCII
  555       else if (!c_isascii (c))
  556     {
  557       /* Non-ASCII character.  Not supported.  */
  558       goto error;
  559     }
  560 #endif
  561     }
  562   d->dir[d->count].dir_start = cp;
  563 
  564   d->max_width_length = max_width_length;
  565   d->max_precision_length = max_precision_length;
  566   return 0;
  567 
  568 error:
  569   if (a->arg)
  570     free (a->arg);
  571   if (d->dir)
  572     free (d->dir);
  573   errno = EINVAL;
  574   return -1;
  575 
  576 out_of_memory:
  577   if (a->arg)
  578     free (a->arg);
  579   if (d->dir)
  580     free (d->dir);
  581 out_of_memory_1:
  582   errno = ENOMEM;
  583   return -1;
  584 }
  585 
  586 #undef PRINTF_PARSE
  587 #undef DIRECTIVES
  588 #undef DIRECTIVE
  589 #undef CHAR_T_ONLY_ASCII
  590 #undef CHAR_T