LCOV - code coverage report
Current view: top level - src - estream-printf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 390 606 64.4 %
Date: 2016-12-21 11:11:56 Functions: 13 22 59.1 %

          Line data    Source code
       1             : /* estream-printf.c - Versatile mostly C-99 compliant printf formatting
       2             :  * Copyright (C) 2007, 2008, 2009, 2010, 2012, 2014 g10 Code GmbH
       3             :  *
       4             :  * This file is part of Libestream.
       5             :  *
       6             :  * Libestream is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * Libestream is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with Libestream; if not, see <https://www.gnu.org/licenses/>.
      18             :  *
      19             :  * ALTERNATIVELY, Libestream may be distributed under the terms of the
      20             :  * following license, in which case the provisions of this license are
      21             :  * required INSTEAD OF the GNU General Public License. If you wish to
      22             :  * allow use of your version of this file only under the terms of the
      23             :  * GNU General Public License, and not to allow others to use your
      24             :  * version of this file under the terms of the following license,
      25             :  * indicate your decision by deleting this paragraph and the license
      26             :  * below.
      27             :  *
      28             :  * Redistribution and use in source and binary forms, with or without
      29             :  * modification, are permitted provided that the following conditions
      30             :  * are met:
      31             :  * 1. Redistributions of source code must retain the above copyright
      32             :  *    notice, and the entire permission notice in its entirety,
      33             :  *    including the disclaimer of warranties.
      34             :  * 2. Redistributions in binary form must reproduce the above copyright
      35             :  *    notice, this list of conditions and the following disclaimer in the
      36             :  *    documentation and/or other materials provided with the distribution.
      37             :  * 3. The name of the author may not be used to endorse or promote
      38             :  *    products derived from this software without specific prior
      39             :  *    written permission.
      40             :  *
      41             :  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
      42             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      43             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      44             :  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      45             :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      46             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      47             :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      48             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      49             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      50             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      51             :  * OF THE POSSIBILITY OF SUCH DAMAGE.
      52             :  */
      53             : 
      54             : /*  Required autoconf tests:
      55             : 
      56             :     AC_TYPE_LONG_LONG_INT            defines HAVE_LONG_LONG_INT
      57             :     AC_TYPE_LONG_DOUBLE              defines HAVE_LONG_DOUBLE
      58             :     AC_TYPE_INTMAX_T                 defines HAVE_INTMAX_T
      59             :     AC_TYPE_UINTMAX_T                defines HAVE_UINTMAX_T
      60             :     AC_CHECK_TYPES([ptrdiff_t])      defines HAVE_PTRDIFF_T
      61             :     AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG
      62             :     AC_CHECK_SIZEOF([void *])        defines SIZEOF_VOID_P
      63             :                                              HAVE_LANGINFO_THOUSANDS_SEP
      64             : 
      65             :     Note that the file estream.m4 provides the autoconf macro
      66             :     ESTREAM_PRINTF_INIT which runs all required checks.
      67             :     See estream-printf.h for ways to tune this code.
      68             : 
      69             :   Missing stuff:  wchar and wint_t
      70             :                   thousands_sep in pr_float.
      71             : 
      72             : */
      73             : 
      74             : #ifdef HAVE_CONFIG_H
      75             : # include <config.h>
      76             : #endif
      77             : 
      78             : #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
      79             : # define HAVE_W32_SYSTEM 1
      80             : # if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
      81             : #  define HAVE_W32CE_SYSTEM
      82             : # endif
      83             : #endif
      84             : 
      85             : #include <stdio.h>
      86             : #include <stdlib.h>
      87             : #include <string.h>
      88             : #include <unistd.h>
      89             : #include <stdarg.h>
      90             : #include <errno.h>
      91             : #include <stddef.h>
      92             : #include <assert.h>
      93             : #if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T)
      94             : # ifdef HAVE_STDINT_H
      95             : #  include <stdint.h>
      96             : # endif
      97             : #endif
      98             : #ifdef HAVE_LANGINFO_THOUSANDS_SEP
      99             : #include <langinfo.h>
     100             : #endif
     101             : #ifdef HAVE_W32CE_SYSTEM
     102             : #include <gpg-error.h>  /* ERRNO replacement.  */
     103             : #endif
     104             : #ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE
     105             : # include _ESTREAM_PRINTF_EXTRA_INCLUDE
     106             : #endif
     107             : #include "estream-printf.h"
     108             : 
     109             : /* #define DEBUG 1 */
     110             : 
     111             : 
     112             : /* Allow redefinition of asprintf used realloc function.  */
     113             : #if defined(_ESTREAM_PRINTF_REALLOC)
     114             : #define my_printf_realloc(a,b) _ESTREAM_PRINTF_REALLOC((a),(b))
     115             : #else
     116             : #define my_printf_realloc(a,b) fixed_realloc((a),(b))
     117             : #endif
     118             : 
     119             : /* A wrapper to set ERRNO.  */
     120             : #ifdef HAVE_W32CE_SYSTEM
     121             : # define _set_errno(a)  gpg_err_set_errno ((a))
     122             : #else
     123             : # define _set_errno(a)  do { errno = (a); } while (0)
     124             : #endif
     125             : 
     126             : 
     127             : /* Calculate array dimension.  */
     128             : #ifndef DIM
     129             : #define DIM(array) (sizeof (array) / sizeof (*array))
     130             : #endif
     131             : 
     132             : 
     133             : /* We allow for that many args without requiring malloced memory. */
     134             : #define DEFAULT_MAX_ARGSPECS  5
     135             : 
     136             : /* We allow for that many values without requiring malloced memory. */
     137             : #define DEFAULT_MAX_VALUES  8
     138             : 
     139             : /* We allocate this many new array argspec elements each time.  */
     140             : #define ARGSPECS_BUMP_VALUE   10
     141             : 
     142             : /* Special values for the field width and the precision.  */
     143             : #define NO_FIELD_VALUE   (-1)
     144             : #define STAR_FIELD_VALUE (-2)
     145             : 
     146             : /* Bit valuues used for the conversion flags. */
     147             : #define FLAG_GROUPING   1
     148             : #define FLAG_LEFT_JUST  2
     149             : #define FLAG_PLUS_SIGN  4
     150             : #define FLAG_SPACE_PLUS 8
     151             : #define FLAG_ALT_CONV   16
     152             : #define FLAG_ZERO_PAD   32
     153             : 
     154             : /* Constants used the length modifiers.  */
     155             : typedef enum
     156             :   {
     157             :     LENMOD_NONE = 0,
     158             :     LENMOD_CHAR,     /* "hh" */
     159             :     LENMOD_SHORT,    /* "h"  */
     160             :     LENMOD_LONG,     /* "l"  */
     161             :     LENMOD_LONGLONG, /* "ll" */
     162             :     LENMOD_INTMAX,   /* "j"  */
     163             :     LENMOD_SIZET,    /* "z"  */
     164             :     LENMOD_PTRDIFF,  /* "t"  */
     165             :     LENMOD_LONGDBL   /* "L"  */
     166             :   } lenmod_t;
     167             : 
     168             : /* All the conversion specifiers.  */
     169             : typedef enum
     170             :   {
     171             :     CONSPEC_UNKNOWN = 0,
     172             :     CONSPEC_DECIMAL,
     173             :     CONSPEC_OCTAL,
     174             :     CONSPEC_UNSIGNED,
     175             :     CONSPEC_HEX,
     176             :     CONSPEC_HEX_UP,
     177             :     CONSPEC_FLOAT,
     178             :     CONSPEC_FLOAT_UP,
     179             :     CONSPEC_EXP,
     180             :     CONSPEC_EXP_UP,
     181             :     CONSPEC_F_OR_G,
     182             :     CONSPEC_F_OR_G_UP,
     183             :     CONSPEC_HEX_EXP,
     184             :     CONSPEC_HEX_EXP_UP,
     185             :     CONSPEC_CHAR,
     186             :     CONSPEC_STRING,
     187             :     CONSPEC_POINTER,
     188             :     CONSPEC_STRERROR,
     189             :     CONSPEC_BYTES_SO_FAR
     190             :   } conspec_t;
     191             : 
     192             : 
     193             : /* Constants describing all the suppoorted types.  Note that we list
     194             :    all the types we know about even if certain types are not available
     195             :    on this system. */
     196             : typedef enum
     197             :   {
     198             :     VALTYPE_UNSUPPORTED = 0,  /* Artificial type for error detection.  */
     199             :     VALTYPE_CHAR,
     200             :     VALTYPE_SCHAR,
     201             :     VALTYPE_UCHAR,
     202             :     VALTYPE_SHORT,
     203             :     VALTYPE_USHORT,
     204             :     VALTYPE_INT,
     205             :     VALTYPE_UINT,
     206             :     VALTYPE_LONG,
     207             :     VALTYPE_ULONG,
     208             :     VALTYPE_LONGLONG,
     209             :     VALTYPE_ULONGLONG,
     210             :     VALTYPE_DOUBLE,
     211             :     VALTYPE_LONGDOUBLE,
     212             :     VALTYPE_STRING,
     213             :     VALTYPE_INTMAX,
     214             :     VALTYPE_UINTMAX,
     215             :     VALTYPE_SIZE,
     216             :     VALTYPE_PTRDIFF,
     217             :     VALTYPE_POINTER,
     218             :     VALTYPE_CHAR_PTR,
     219             :     VALTYPE_SCHAR_PTR,
     220             :     VALTYPE_SHORT_PTR,
     221             :     VALTYPE_INT_PTR,
     222             :     VALTYPE_LONG_PTR,
     223             :     VALTYPE_LONGLONG_PTR,
     224             :     VALTYPE_INTMAX_PTR,
     225             :     VALTYPE_SIZE_PTR,
     226             :     VALTYPE_PTRDIFF_PTR
     227             :   } valtype_t;
     228             : 
     229             : 
     230             : /* A union used to store the actual values. */
     231             : typedef union
     232             : {
     233             :   char a_char;
     234             :   signed char a_schar;
     235             :   unsigned char a_uchar;
     236             :   short a_short;
     237             :   unsigned short a_ushort;
     238             :   int a_int;
     239             :   unsigned int a_uint;
     240             :   long int a_long;
     241             :   unsigned long int a_ulong;
     242             : #ifdef HAVE_LONG_LONG_INT
     243             :   long long int a_longlong;
     244             :   unsigned long long int a_ulonglong;
     245             : #endif
     246             :   double a_double;
     247             : #ifdef HAVE_LONG_DOUBLE
     248             :   long double a_longdouble;
     249             : #endif
     250             :   const char *a_string;
     251             : #ifdef HAVE_INTMAX_T
     252             :   intmax_t a_intmax;
     253             : #endif
     254             : #ifdef HAVE_UINTMAX_T
     255             :   intmax_t a_uintmax;
     256             : #endif
     257             :   size_t a_size;
     258             : #ifdef HAVE_PTRDIFF_T
     259             :   ptrdiff_t a_ptrdiff;
     260             : #endif
     261             :   void *a_void_ptr;
     262             :   char *a_char_ptr;
     263             :   signed char *a_schar_ptr;
     264             :   short *a_short_ptr;
     265             :   int  *a_int_ptr;
     266             :   long *a_long_ptr;
     267             : #ifdef HAVE_LONG_LONG_INT
     268             :   long long int *a_longlong_ptr;
     269             : #endif
     270             : #ifdef HAVE_INTMAX_T
     271             :   intmax_t *a_intmax_ptr;
     272             : #endif
     273             :   size_t *a_size_ptr;
     274             : #ifdef HAVE_PTRDIFF_T
     275             :   ptrdiff_t *a_ptrdiff_ptr;
     276             : #endif
     277             : } value_t;
     278             : 
     279             : /* An object used to keep track of a format option and arguments. */
     280             : struct argspec_s
     281             : {
     282             :   size_t length;       /* The length of these args including the percent.  */
     283             :   unsigned int flags;  /* The conversion flags (bits defined by FLAG_foo).  */
     284             :   int width;           /* The field width.  */
     285             :   int precision;       /* The precision.  */
     286             :   lenmod_t lenmod;     /* The length modifier.  */
     287             :   conspec_t conspec;   /* The conversion specifier.  */
     288             :   int arg_pos;         /* The position of the argument.  This one may
     289             :                           be -1 to indicate that no value is expected
     290             :                           (e.g. for "%m").  */
     291             :   int width_pos;       /* The position of the argument for a field
     292             :                           width star's value. 0 for not used.  */
     293             :   int precision_pos;   /* The position of the argument for the a
     294             :                           precision star's value.  0 for not used. */
     295             :   valtype_t vt;        /* The type of the corresponding argument.  */
     296             : };
     297             : typedef struct argspec_s *argspec_t;
     298             : 
     299             : /* An object to build up a table of values and their types.  */
     300             : struct valueitem_s
     301             : {
     302             :   valtype_t vt;  /* The type of the value.  */
     303             :   value_t value; /* The value.  */
     304             : };
     305             : typedef struct valueitem_s *valueitem_t;
     306             : 
     307             : 
     308             : /* Not all systems have a C-90 compliant realloc.  To cope with this
     309             :    we use this simple wrapper. */
     310             : #ifndef _ESTREAM_PRINTF_REALLOC
     311             : static void *
     312             : fixed_realloc (void *a, size_t n)
     313             : {
     314             :   if (!a)
     315             :     return malloc (n);
     316             : 
     317             :   if (!n)
     318             :     {
     319             :       free (a);
     320             :       return NULL;
     321             :     }
     322             : 
     323             :   return realloc (a, n);
     324             : }
     325             : #endif /*!_ESTREAM_PRINTF_REALLOC*/
     326             : 
     327             : 
     328             : #ifdef DEBUG
     329             : static void
     330             : dump_argspecs (argspec_t arg, size_t argcount)
     331             : {
     332             :   int idx;
     333             : 
     334             :   for (idx=0; argcount; argcount--, arg++, idx++)
     335             :     fprintf (stderr,
     336             :              "%2d: len=%u flags=%u width=%d prec=%d mod=%d "
     337             :              "con=%d vt=%d pos=%d-%d-%d\n",
     338             :              idx,
     339             :              (unsigned int)arg->length,
     340             :              arg->flags,
     341             :              arg->width,
     342             :              arg->precision,
     343             :              arg->lenmod,
     344             :              arg->conspec,
     345             :              arg->vt,
     346             :              arg->arg_pos,
     347             :              arg->width_pos,
     348             :              arg->precision_pos);
     349             : }
     350             : #endif /*DEBUG*/
     351             : 
     352             : 
     353             : /* Set the vt field for ARG.  */
     354             : static void
     355         453 : compute_type (argspec_t arg)
     356             : {
     357         453 :   switch (arg->conspec)
     358             :     {
     359             :     case CONSPEC_UNKNOWN:
     360           0 :       arg->vt = VALTYPE_UNSUPPORTED;
     361             :       break;
     362             : 
     363             :     case CONSPEC_DECIMAL:
     364         233 :       switch (arg->lenmod)
     365             :         {
     366           0 :         case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break;
     367           0 :         case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break;
     368           0 :         case LENMOD_LONG: arg->vt = VALTYPE_LONG; break;
     369           0 :         case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break;
     370           0 :         case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break;
     371           0 :         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;
     372           0 :         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
     373         233 :         default: arg->vt = VALTYPE_INT; break;
     374             :         }
     375             :       break;
     376             : 
     377             :     case CONSPEC_OCTAL:
     378             :     case CONSPEC_UNSIGNED:
     379             :     case CONSPEC_HEX:
     380             :     case CONSPEC_HEX_UP:
     381          96 :       switch (arg->lenmod)
     382             :         {
     383           0 :         case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break;
     384           0 :         case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break;
     385           0 :         case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break;
     386           0 :         case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break;
     387           0 :         case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break;
     388           0 :         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;
     389           0 :         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
     390          96 :         default: arg->vt = VALTYPE_UINT; break;
     391             :         }
     392             :       break;
     393             : 
     394             :     case CONSPEC_FLOAT:
     395             :     case CONSPEC_FLOAT_UP:
     396             :     case CONSPEC_EXP:
     397             :     case CONSPEC_EXP_UP:
     398             :     case CONSPEC_F_OR_G:
     399             :     case CONSPEC_F_OR_G_UP:
     400             :     case CONSPEC_HEX_EXP:
     401             :     case CONSPEC_HEX_EXP_UP:
     402          84 :       switch (arg->lenmod)
     403             :         {
     404           6 :         case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break;
     405           0 :         case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break;
     406          78 :         default: arg->vt = VALTYPE_DOUBLE; break;
     407             :         }
     408             :       break;
     409             : 
     410             :     case CONSPEC_CHAR:
     411           0 :       arg->vt = VALTYPE_INT;
     412             :       break;
     413             : 
     414             :     case CONSPEC_STRING:
     415          34 :       arg->vt = VALTYPE_STRING;
     416             :       break;
     417             : 
     418             :     case CONSPEC_POINTER:
     419           0 :       arg->vt = VALTYPE_POINTER;
     420             :       break;
     421             : 
     422             :     case CONSPEC_STRERROR:
     423           6 :       arg->vt = VALTYPE_STRING;
     424             :       break;
     425             : 
     426             :     case CONSPEC_BYTES_SO_FAR:
     427           0 :       switch (arg->lenmod)
     428             :         {
     429           0 :         case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break;
     430           0 :         case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break;
     431           0 :         case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break;
     432           0 :         case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break;
     433           0 :         case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break;
     434           0 :         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break;
     435           0 :         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break;
     436           0 :         default: arg->vt = VALTYPE_INT_PTR; break;
     437             :         }
     438             :       break;
     439             : 
     440             :     }
     441         453 : }
     442             : 
     443             : 
     444             : 
     445             : /* Parse the FORMAT string and populate the specification array stored
     446             :    at the address ARGSPECS_ADDR.  The caller has provided enough space
     447             :    to store up to MAX_ARGSPECS in that buffer.  The function may
     448             :    however ignore the provided buffer and malloc a larger one.  On
     449             :    success the address of that larger buffer will be stored at
     450             :    ARGSPECS_ADDR.  The actual number of specifications will be
     451             :    returned at R_ARGSPECS_COUNT. */
     452             : static int
     453         335 : parse_format (const char *format,
     454             :               argspec_t *argspecs_addr, size_t max_argspecs,
     455             :               size_t *r_argspecs_count)
     456             : {
     457             :   const char *s;
     458         335 :   argspec_t argspecs = *argspecs_addr;
     459             :   argspec_t arg;
     460             :   size_t argcount = 0;
     461             : 
     462         335 :   if (!format)
     463             :     goto leave_einval;
     464             : 
     465         550 :   for (; *format; format++)
     466             :     {
     467             :       unsigned int flags;
     468             :       int width, precision;
     469             :       lenmod_t lenmod;
     470             :       conspec_t conspec;
     471             :       int arg_pos, width_pos, precision_pos;
     472             : 
     473         550 :       if (*format != '%')
     474          93 :         continue;
     475         457 :       s = ++format;
     476         457 :       if (!*s)
     477             :         goto leave_einval;
     478         457 :       if (*s == '%')
     479           4 :         continue; /* Just a quoted percent.  */
     480             : 
     481             :       /* First check whether there is a positional argument.  */
     482             :       arg_pos = 0; /* No positional argument given.  */
     483         453 :       if (*s >= '1' && *s <= '9')
     484             :         {
     485             :           const char *save_s = s;
     486             : 
     487          50 :           arg_pos = (*s++ - '0');
     488          82 :           for (; *s >= '0' && *s <= '9'; s++)
     489          32 :             arg_pos = 10*arg_pos + (*s - '0');
     490          50 :           if (arg_pos < 0)
     491             :             goto leave_einval; /* Overflow during conversion.  */
     492          50 :           if (*s == '$')
     493           4 :             s++;
     494             :           else
     495             :             {
     496             :               arg_pos = 0;
     497             :               s = save_s;
     498             :             }
     499             :         }
     500             : 
     501             :       /* Parse the flags.  */
     502             :       flags = 0;
     503         717 :       for ( ; *s; s++)
     504             :         {
     505         717 :           switch (*s)
     506             :             {
     507           0 :             case '\'': flags |= FLAG_GROUPING; break;
     508          50 :             case '-': flags |= FLAG_LEFT_JUST; break;
     509          12 :             case '+': flags |= FLAG_PLUS_SIGN; break;
     510          12 :             case ' ': flags |= FLAG_SPACE_PLUS; break;
     511          58 :             case '#': flags |= FLAG_ALT_CONV; break;
     512         132 :             case '0': flags |= FLAG_ZERO_PAD; break;
     513             :             default:
     514             :               goto flags_parsed;
     515             :             }
     516             :         }
     517             :     flags_parsed:
     518             : 
     519             :       /* Parse the field width.  */
     520             :       width_pos = 0;
     521         453 :       if (*s == '*')
     522             :         {
     523             :           width = STAR_FIELD_VALUE;
     524          89 :           s++;
     525             :           /* If we have a positional argument, another one might also
     526             :              be used to give the position of the star's value. */
     527          89 :           if (arg_pos && *s >= '1' && *s <= '9')
     528             :             {
     529           0 :               width_pos = (*s++ - '0');
     530           0 :               for (; *s >= '0' && *s <= '9'; s++)
     531           0 :                 width_pos = 10*width_pos + (*s - '0');
     532           0 :               if (width_pos < 1)
     533             :                 goto leave_einval; /* Overflow during conversion.  */
     534           0 :               if (*s != '$')
     535             :                 goto leave_einval; /* Not followed by $.  */
     536           0 :               s++;
     537             :             }
     538             :         }
     539         364 :       else if ( *s >= '0' && *s <= '9')
     540             :         {
     541         238 :           width = (*s++ - '0');
     542         310 :           for (; *s >= '0' && *s <= '9'; s++)
     543             :             {
     544          72 :               if (!width && *s == '0')
     545             :                 goto leave_einval; /* Leading zeroes are not allowed.
     546             :                                       Fixme: check what other
     547             :                                       implementations do. */
     548          72 :               width = 10*width + (*s - '0');
     549             :             }
     550         238 :           if (width < 0)
     551             :             goto leave_einval; /* Overflow during conversion.  */
     552             :         }
     553             :       else
     554             :         width = NO_FIELD_VALUE;
     555             : 
     556             :       /* Parse the precision.  */
     557             :       precision_pos = 0;
     558             :       precision = NO_FIELD_VALUE;
     559         453 :       if (*s == '.')
     560             :         {
     561         186 :           int ignore_value = (s[1] == '-');
     562             : 
     563         186 :           s++;
     564         186 :           if (*s == '*')
     565             :             {
     566             :               precision = STAR_FIELD_VALUE;
     567          84 :               s++;
     568             :               /* If we have a positional argument, another one might also
     569             :                  be used to give the position of the star's value. */
     570          84 :               if (arg_pos && *s >= '1' && *s <= '9')
     571             :                 {
     572           0 :                   precision_pos = (*s++ - '0');
     573           0 :                   for (; *s >= '0' && *s <= '9'; s++)
     574           0 :                     precision_pos = 10*precision_pos + (*s - '0');
     575           0 :                   if (precision_pos < 1)
     576             :                     goto leave_einval; /* Overflow during conversion.  */
     577           0 :                   if (*s != '$')
     578             :                     goto leave_einval; /* Not followed by $.  */
     579           0 :                   s++;
     580             :                 }
     581             :             }
     582         102 :           else if ( *s >= '0' && *s <= '9')
     583             :             {
     584         100 :               precision = (*s++ - '0');
     585         130 :               for (; *s >= '0' && *s <= '9'; s++)
     586             :                 {
     587          30 :                   if (!precision && *s == '0')
     588             :                     goto leave_einval; /* Leading zeroes are not allowed.
     589             :                                           Fixme: check what other
     590             :                                           implementations do. */
     591          30 :                   precision = 10*precision + (*s - '0');
     592             :                 }
     593         100 :               if (precision < 0)
     594             :                 goto leave_einval; /* Overflow during conversion.  */
     595             :             }
     596             :           else
     597             :             precision = 0;
     598         186 :           if (ignore_value)
     599             :             precision = NO_FIELD_VALUE;
     600             :         }
     601             : 
     602             :       /* Parse the length modifiers.  */
     603         453 :       switch (*s)
     604             :         {
     605             :         case 'h':
     606           0 :           if (s[1] == 'h')
     607             :             {
     608             :               lenmod = LENMOD_CHAR;
     609           0 :               s++;
     610             :             }
     611             :           else
     612             :             lenmod = LENMOD_SHORT;
     613           0 :           s++;
     614           0 :           break;
     615             :         case 'l':
     616           0 :           if (s[1] == 'l')
     617             :             {
     618             :               lenmod = LENMOD_LONGLONG;
     619           0 :               s++;
     620             :             }
     621             :           else
     622             :             lenmod = LENMOD_LONG;
     623           0 :           s++;
     624           0 :           break;
     625           0 :         case 'j': lenmod = LENMOD_INTMAX; s++; break;
     626           0 :         case 'z': lenmod = LENMOD_SIZET; s++; break;
     627           0 :         case 't': lenmod = LENMOD_PTRDIFF; s++; break;
     628           6 :         case 'L': lenmod = LENMOD_LONGDBL; s++; break;
     629             :         default:  lenmod = LENMOD_NONE; break;
     630             :         }
     631             : 
     632             :       /* Parse the conversion specifier.  */
     633         453 :       switch (*s)
     634             :         {
     635             :         case 'd':
     636             :         case 'i': conspec = CONSPEC_DECIMAL; break;
     637          32 :         case 'o': conspec = CONSPEC_OCTAL; break;
     638           0 :         case 'u': conspec = CONSPEC_UNSIGNED; break;
     639          32 :         case 'x': conspec = CONSPEC_HEX; break;
     640          32 :         case 'X': conspec = CONSPEC_HEX_UP; break;
     641          68 :         case 'f': conspec = CONSPEC_FLOAT; break;
     642           0 :         case 'F': conspec = CONSPEC_FLOAT_UP; break;
     643           2 :         case 'e': conspec = CONSPEC_EXP; break;
     644           0 :         case 'E': conspec = CONSPEC_EXP_UP; break;
     645           2 :         case 'g': conspec = CONSPEC_F_OR_G; break;
     646           0 :         case 'G': conspec = CONSPEC_F_OR_G_UP; break;
     647          12 :         case 'a': conspec = CONSPEC_HEX_EXP; break;
     648           0 :         case 'A': conspec = CONSPEC_HEX_EXP_UP; break;
     649           0 :         case 'c': conspec = CONSPEC_CHAR; break;
     650          34 :         case 's': conspec = CONSPEC_STRING; break;
     651           0 :         case 'p': conspec = CONSPEC_POINTER; break;
     652           0 :         case 'n': conspec = CONSPEC_BYTES_SO_FAR; break;
     653           0 :         case 'C': conspec = CONSPEC_CHAR; lenmod = LENMOD_LONG; break;
     654           0 :         case 'S': conspec = CONSPEC_STRING; lenmod = LENMOD_LONG; break;
     655           6 :         case 'm': conspec = CONSPEC_STRERROR; arg_pos = -1; break;
     656             :         default: conspec = CONSPEC_UNKNOWN;
     657             :         }
     658             : 
     659             :       /* Save the args. */
     660         453 :       if (argcount >= max_argspecs)
     661             :         {
     662             :           /* We either need to allocate a new array instead of the
     663             :              caller provided one or realloc the array.  Instead of
     664             :              using realloc we allocate a new one and release the
     665             :              original one then. */
     666             :           size_t n, newmax;
     667             :           argspec_t newarg;
     668             : 
     669          21 :           newmax = max_argspecs + ARGSPECS_BUMP_VALUE;
     670          21 :           if (newmax <= max_argspecs)
     671             :             goto leave_einval;  /* Too many arguments. */
     672          21 :           newarg = calloc (newmax, sizeof *newarg);
     673          21 :           if (!newarg)
     674             :             goto leave;
     675         105 :           for (n=0; n < argcount; n++)
     676         105 :             newarg[n] = argspecs[n];
     677          21 :           if (argspecs != *argspecs_addr)
     678           0 :             free (argspecs);
     679             :           argspecs = newarg;
     680             :           max_argspecs = newmax;
     681             :         }
     682             : 
     683         453 :       arg = argspecs + argcount;
     684         453 :       arg->length = s - format + 2;
     685         453 :       arg->flags = flags;
     686         453 :       arg->width = width;
     687         453 :       arg->precision = precision;
     688         453 :       arg->lenmod = lenmod;
     689         453 :       arg->conspec = conspec;
     690         453 :       arg->arg_pos = arg_pos;
     691         453 :       arg->width_pos = width_pos;
     692         453 :       arg->precision_pos = precision_pos;
     693         453 :       compute_type (arg);
     694         453 :       argcount++;
     695             :       format = s;
     696             :     }
     697             : 
     698         335 :   *argspecs_addr = argspecs;
     699         335 :   *r_argspecs_count = argcount;
     700         335 :   return 0; /* Success.  */
     701             : 
     702             :  leave_einval:
     703           0 :   _set_errno (EINVAL);
     704             :  leave:
     705           0 :   if (argspecs != *argspecs_addr)
     706           0 :     free (argspecs);
     707           0 :   *argspecs_addr = NULL;
     708           0 :   return -1;
     709             : }
     710             : 
     711             : 
     712             : /* This function reads all the values as specified by VALUETABLE into
     713             :    VALUETABLE.  The values are expected in VAARGS.  The function
     714             :    returns -1 if a specified type is not supported. */
     715             : static int
     716         335 : read_values (valueitem_t valuetable, size_t valuetable_len, va_list vaargs)
     717             : {
     718             :   int validx;
     719             : 
     720         955 :   for (validx=0; validx < valuetable_len; validx++)
     721             :     {
     722         620 :       value_t *value = &valuetable[validx].value;
     723         620 :       valtype_t vt = valuetable[validx].vt;
     724             : 
     725         620 :       switch (vt)
     726             :         {
     727           0 :         case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break;
     728             :         case VALTYPE_CHAR_PTR:
     729           0 :           value->a_char_ptr = va_arg (vaargs, char *);
     730           0 :           break;
     731           0 :         case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break;
     732             :         case VALTYPE_SCHAR_PTR:
     733           0 :           value->a_schar_ptr = va_arg (vaargs, signed char *);
     734           0 :           break;
     735           0 :         case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break;
     736           0 :         case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break;
     737           0 :         case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break;
     738             :         case VALTYPE_SHORT_PTR:
     739           0 :           value->a_short_ptr = va_arg (vaargs, short *);
     740           0 :           break;
     741             :         case VALTYPE_INT:
     742         406 :           value->a_int = va_arg (vaargs, int);
     743         406 :           break;
     744             :         case VALTYPE_INT_PTR:
     745           0 :           value->a_int_ptr = va_arg (vaargs, int *);
     746           0 :           break;
     747             :         case VALTYPE_UINT:
     748          96 :           value->a_uint = va_arg (vaargs, unsigned int);
     749          96 :           break;
     750             :         case VALTYPE_LONG:
     751           0 :           value->a_long = va_arg (vaargs, long);
     752           0 :           break;
     753             :         case VALTYPE_ULONG:
     754           0 :           value->a_ulong = va_arg (vaargs, unsigned long);
     755           0 :           break;
     756             :         case VALTYPE_LONG_PTR:
     757           0 :           value->a_long_ptr = va_arg (vaargs, long *);
     758           0 :           break;
     759             : #ifdef HAVE_LONG_LONG_INT
     760             :         case VALTYPE_LONGLONG:
     761           0 :           value->a_longlong = va_arg (vaargs, long long int);
     762           0 :           break;
     763             :         case VALTYPE_ULONGLONG:
     764           0 :           value->a_ulonglong = va_arg (vaargs, unsigned long long int);
     765           0 :           break;
     766             :         case VALTYPE_LONGLONG_PTR:
     767           0 :           value->a_longlong_ptr = va_arg (vaargs, long long *);
     768           0 :           break;
     769             : #endif
     770             :         case VALTYPE_DOUBLE:
     771          78 :           value->a_double = va_arg (vaargs, double);
     772          78 :           break;
     773             : #ifdef HAVE_LONG_DOUBLE
     774             :         case VALTYPE_LONGDOUBLE:
     775           6 :           value->a_longdouble = va_arg (vaargs, long double);
     776           6 :           break;
     777             : #endif
     778             :         case VALTYPE_STRING:
     779          34 :           value->a_string = va_arg (vaargs, const char *);
     780          34 :           break;
     781             :         case VALTYPE_POINTER:
     782           0 :           value->a_void_ptr = va_arg (vaargs, void *);
     783           0 :           break;
     784             : #ifdef HAVE_INTMAX_T
     785             :         case VALTYPE_INTMAX:
     786           0 :           value->a_intmax = va_arg (vaargs, intmax_t);
     787           0 :           break;
     788             :         case VALTYPE_INTMAX_PTR:
     789           0 :           value->a_intmax_ptr = va_arg (vaargs, intmax_t *);
     790           0 :           break;
     791             : #endif
     792             : #ifdef HAVE_UINTMAX_T
     793             :         case VALTYPE_UINTMAX:
     794           0 :           value->a_uintmax = va_arg (vaargs, uintmax_t);
     795           0 :           break;
     796             : #endif
     797             :         case VALTYPE_SIZE:
     798           0 :           value->a_size = va_arg (vaargs, size_t);
     799           0 :           break;
     800             :         case VALTYPE_SIZE_PTR:
     801           0 :           value->a_size_ptr = va_arg (vaargs, size_t *);
     802           0 :           break;
     803             : #ifdef HAVE_PTRDIFF_T
     804             :         case VALTYPE_PTRDIFF:
     805           0 :           value->a_ptrdiff = va_arg (vaargs, ptrdiff_t);
     806           0 :           break;
     807             :         case VALTYPE_PTRDIFF_PTR:
     808           0 :           value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *);
     809           0 :           break;
     810             : #endif
     811             :         default: /* Unsupported type.  */
     812             :           return -1;
     813             :         }
     814             :     }
     815             :   return 0;
     816             : }
     817             : 
     818             : 
     819             : 
     820             : /* Output COUNT padding characters PADCHAR and update NBYTES by the
     821             :    number of bytes actually written.  */
     822             : static int
     823         373 : pad_out (estream_printf_out_t outfnc, void *outfncarg,
     824             :          int padchar, int count, size_t *nbytes)
     825             : {
     826             :   char buf[32];
     827             :   size_t n;
     828             :   int rc;
     829             : 
     830        1066 :   while (count > 0)
     831             :     {
     832         320 :       n = (count <= sizeof buf)? count : sizeof buf;
     833         320 :       memset (buf, padchar, n);
     834         320 :       rc = outfnc (outfncarg, buf, n);
     835         320 :       if (rc)
     836             :         return rc;
     837         320 :       *nbytes += n;
     838         320 :       count -= n;
     839             :     }
     840             : 
     841             :   return 0;
     842             : }
     843             : 
     844             : 
     845             : /* "d,i,o,u,x,X" formatting.  OUTFNC and OUTFNCARG describes the
     846             :    output routine, ARG gives the argument description and VALUE the
     847             :    actual value (its type is available through arg->vt).  */
     848             : static int
     849         329 : pr_integer (estream_printf_out_t outfnc, void *outfncarg,
     850             :             argspec_t arg, value_t value, size_t *nbytes)
     851             : {
     852             :   int rc;
     853             : #ifdef HAVE_LONG_LONG_INT
     854             :   unsigned long long aulong;
     855             : #else
     856             :   unsigned long aulong;
     857             : #endif
     858             :   char numbuf[100];
     859             :   char *p, *pend;
     860             :   size_t n;
     861         329 :   char signchar = 0;
     862             :   int n_prec;  /* Number of extra precision digits required.  */
     863             :   int n_extra; /* Extra number of prefix or sign characters.  */
     864             : 
     865         329 :   if (arg->conspec == CONSPEC_DECIMAL)
     866             :     {
     867             : #ifdef HAVE_LONG_LONG_INT
     868             :       long long along;
     869             : #else
     870             :       long along;
     871             : #endif
     872             : 
     873         233 :       switch (arg->vt)
     874             :         {
     875           0 :         case VALTYPE_SHORT: along = value.a_short; break;
     876         233 :         case VALTYPE_INT: along = value.a_int; break;
     877           0 :         case VALTYPE_LONG: along = value.a_long; break;
     878             : #ifdef HAVE_LONG_LONG_INT
     879           0 :         case VALTYPE_LONGLONG: along = value.a_longlong; break;
     880           0 :         case VALTYPE_SIZE: along = value.a_size; break;
     881             : # ifdef HAVE_INTMAX_T
     882           0 :         case VALTYPE_INTMAX: along = value.a_intmax; break;
     883             : # endif
     884             : # ifdef HAVE_PTRDIFF_T
     885           0 :         case VALTYPE_PTRDIFF: along = value.a_ptrdiff; break;
     886             : # endif
     887             : #endif /*HAVE_LONG_LONG_INT*/
     888             :         default:
     889             :           return -1;
     890             :         }
     891         233 :       if (along < 0)
     892             :         {
     893          34 :           aulong = -along;
     894          34 :           signchar = '-';
     895             :         }
     896             :       else
     897         199 :         aulong = along;
     898             :     }
     899             :   else
     900             :     {
     901          96 :       switch (arg->vt)
     902             :         {
     903           0 :         case VALTYPE_USHORT: aulong = value.a_ushort; break;
     904          96 :         case VALTYPE_UINT: aulong = value.a_uint; break;
     905           0 :         case VALTYPE_ULONG: aulong = value.a_ulong; break;
     906             : #ifdef HAVE_LONG_LONG_INT
     907           0 :         case VALTYPE_ULONGLONG: aulong = value.a_ulonglong; break;
     908           0 :         case VALTYPE_SIZE: aulong = value.a_size; break;
     909             : # ifdef HAVE_UINTMAX_T
     910           0 :         case VALTYPE_UINTMAX: aulong = value.a_uintmax; break;
     911             : # endif
     912             : # ifdef HAVE_PTRDIFF_T
     913           0 :         case VALTYPE_PTRDIFF: aulong = value.a_ptrdiff; break;
     914             : # endif
     915             : #endif /*HAVE_LONG_LONG_INT*/
     916             :         default:
     917             :           return -1;
     918             :         }
     919             :     }
     920             : 
     921         329 :   if (signchar == '-')
     922             :     ;
     923         295 :   else if ((arg->flags & FLAG_PLUS_SIGN))
     924           6 :     signchar = '+';
     925         289 :   else if ((arg->flags & FLAG_SPACE_PLUS))
     926           6 :     signchar = ' ';
     927             : 
     928         329 :   n_extra = !!signchar;
     929             : 
     930             :   /* We build the string up backwards.  */
     931             :   p = pend = numbuf + DIM(numbuf);
     932         329 :   if ((!aulong && !arg->precision))
     933             :     ;
     934         321 :   else if (arg->conspec == CONSPEC_DECIMAL
     935         321 :            || arg->conspec == CONSPEC_UNSIGNED)
     936             :     {
     937             :       int grouping = -1;
     938         225 :       const char * grouping_string =
     939             : #ifdef HAVE_LANGINFO_THOUSANDS_SEP
     940             :         nl_langinfo(THOUSANDS_SEP);
     941             : #else
     942             :         "'";
     943             : #endif
     944             : 
     945             :       do
     946             :         {
     947         454 :           if ((arg->flags & FLAG_GROUPING)
     948           0 :               && (++grouping == 3) && *grouping_string)
     949             :             {
     950           0 :               *--p = *grouping_string;
     951             :               grouping = 0;
     952             :             }
     953         454 :           *--p = '0' + (aulong % 10);
     954         454 :           aulong /= 10;
     955             :         }
     956         454 :       while (aulong);
     957             :     }
     958          96 :   else if (arg->conspec == CONSPEC_OCTAL)
     959             :     {
     960             :       do
     961             :         {
     962          64 :           *--p = '0' + (aulong % 8);
     963          64 :           aulong /= 8;
     964             :         }
     965          64 :       while (aulong);
     966          32 :       if ((arg->flags & FLAG_ALT_CONV) && *p != '0')
     967          16 :         *--p = '0';
     968             :     }
     969             :   else /* HEX or HEXUP */
     970             :     {
     971          64 :       const char *digits = ((arg->conspec == CONSPEC_HEX)
     972             :                             ? "0123456789abcdef" : "0123456789ABCDEF");
     973             :       do
     974             :         {
     975         128 :           *--p = digits[(aulong % 16)];
     976         128 :           aulong /= 16;
     977             :         }
     978         128 :       while (aulong);
     979          64 :       if ((arg->flags & FLAG_ALT_CONV))
     980          32 :         n_extra += 2;
     981             :     }
     982             : 
     983         329 :   n = pend - p;
     984             : 
     985         329 :   if ((arg->flags & FLAG_ZERO_PAD)
     986         132 :       && arg->precision == NO_FIELD_VALUE && !(arg->flags & FLAG_LEFT_JUST)
     987         130 :       && n && arg->width - n_extra > n )
     988          67 :     n_prec = arg->width - n_extra - n;
     989         262 :   else if (arg->precision > 0 && arg->precision > n)
     990          60 :     n_prec = arg->precision - n;
     991             :   else
     992             :     n_prec = 0;
     993             : 
     994         329 :   if (!(arg->flags & FLAG_LEFT_JUST)
     995         267 :       && arg->width >= 0 && arg->width - n_extra > n
     996         139 :       && arg->width - n_extra - n >= n_prec )
     997             :     {
     998         133 :       rc = pad_out (outfnc, outfncarg, ' ',
     999         133 :                     arg->width - n_extra - n - n_prec, nbytes);
    1000         133 :       if (rc)
    1001             :         return rc;
    1002             :     }
    1003             : 
    1004         329 :   if (signchar)
    1005             :     {
    1006          46 :       rc = outfnc (outfncarg, &signchar, 1);
    1007          46 :       if (rc)
    1008             :         return rc;
    1009          46 :       *nbytes += 1;
    1010             :     }
    1011             : 
    1012         329 :   if ((arg->flags & FLAG_ALT_CONV)
    1013          48 :       && (arg->conspec == CONSPEC_HEX || arg->conspec == CONSPEC_HEX_UP))
    1014             :     {
    1015          32 :       rc = outfnc (outfncarg, arg->conspec == CONSPEC_HEX? "0x": "0X", 2);
    1016          32 :       if (rc)
    1017             :         return rc;
    1018          32 :       *nbytes += 2;
    1019             :     }
    1020             : 
    1021         329 :   if (n_prec)
    1022             :     {
    1023         127 :       rc = pad_out (outfnc, outfncarg, '0', n_prec, nbytes);
    1024         127 :       if (rc)
    1025             :         return rc;
    1026             :     }
    1027             : 
    1028         329 :   rc = outfnc (outfncarg, p, pend - p);
    1029         329 :   if (rc)
    1030             :     return rc;
    1031         329 :   *nbytes += pend - p;
    1032             : 
    1033         329 :   if ((arg->flags & FLAG_LEFT_JUST)
    1034          62 :       && arg->width >= 0 && arg->width - n_extra - n_prec > n)
    1035             :     {
    1036          58 :       rc = pad_out (outfnc, outfncarg, ' ',
    1037          58 :                     arg->width - n_extra - n_prec - n, nbytes);
    1038          58 :       if (rc)
    1039             :         return rc;
    1040             :     }
    1041             : 
    1042             :   return 0;
    1043             : }
    1044             : 
    1045             : 
    1046             : /* "e,E,f,F,g,G,a,A" formatting.  OUTFNC and OUTFNCARG describes the
    1047             :    output routine, ARG gives the argument description and VALUE the
    1048             :    actual value (its type is available through arg->vt).  For
    1049             :    portability reasons sprintf is used for the actual formatting.
    1050             :    This is useful because sprint is the only standard function to
    1051             :    convert a floating number into its ascii representation.  To avoid
    1052             :    using malloc we just pass the precision to sprintf and do the final
    1053             :    formatting with our own code.  */
    1054             : static int
    1055          84 : pr_float (estream_printf_out_t outfnc, void *outfncarg,
    1056             :           argspec_t arg, value_t value, size_t *nbytes)
    1057             : {
    1058             :   int rc;
    1059             : #ifdef HAVE_LONG_DOUBLE
    1060             :   long double adblfloat = 0; /* Just to please gcc.  */
    1061             :   int use_dbl = 0;
    1062             : #endif
    1063             :   double afloat;
    1064             :   char numbuf[350];
    1065             :   char formatstr[20];
    1066             :   char *p, *pend;
    1067             :   size_t n;
    1068          84 :   char signchar = 0;
    1069             :   int n_extra;  /* Extra number of prefix or sign characters.  */
    1070             : 
    1071          84 :   switch (arg->vt)
    1072             :     {
    1073          78 :     case VALTYPE_DOUBLE: afloat = value.a_double; break;
    1074             : #ifdef HAVE_LONG_DOUBLE
    1075             :     case VALTYPE_LONGDOUBLE:
    1076             :       afloat = 0;  /* Just to please gcc.  */
    1077           6 :       adblfloat = value.a_longdouble;
    1078           6 :       use_dbl=1; break;
    1079             : #endif
    1080             :     default:
    1081             :       return -1;
    1082             :     }
    1083             : 
    1084             :   /* We build the string using sprint.  */
    1085             :   p = formatstr + sizeof formatstr;
    1086          84 :   *--p = 0;
    1087          84 :   switch (arg->conspec)
    1088             :     {
    1089          68 :     case CONSPEC_FLOAT:      *--p = 'f'; break;
    1090           0 :     case CONSPEC_FLOAT_UP:   *--p = 'F'; break;
    1091           2 :     case CONSPEC_EXP:        *--p = 'e'; break;
    1092           0 :     case CONSPEC_EXP_UP:     *--p = 'E'; break;
    1093           2 :     case CONSPEC_F_OR_G:     *--p = 'g'; break;
    1094           0 :     case CONSPEC_F_OR_G_UP:  *--p = 'G'; break;
    1095          12 :     case CONSPEC_HEX_EXP:    *--p = 'a'; break;
    1096           0 :     case CONSPEC_HEX_EXP_UP: *--p = 'A'; break;
    1097             :     default:
    1098             :       return -1; /* Actually a bug.  */
    1099             :     }
    1100             : #ifdef HAVE_LONG_DOUBLE
    1101          84 :   if (use_dbl)
    1102           6 :     *--p = 'L';
    1103             : #endif
    1104          84 :   if (arg->precision != NO_FIELD_VALUE)
    1105             :     {
    1106             :       /* Limit it to a meaningful value so that even a stupid sprintf
    1107             :          won't overflow our buffer.  */
    1108          60 :       n = arg->precision <= 100? arg->precision : 100;
    1109             :       do
    1110             :         {
    1111          80 :           *--p = '0' + (n % 10);
    1112          80 :           n /= 10;
    1113             :         }
    1114          80 :       while (n);
    1115          60 :       *--p = '.';
    1116             :     }
    1117          84 :   if ((arg->flags & FLAG_ALT_CONV))
    1118          10 :     *--p = '#';
    1119          84 :   *--p = '%';
    1120             : #ifdef HAVE_LONG_DOUBLE
    1121          84 :   if (use_dbl)
    1122           6 :     sprintf (numbuf, p, adblfloat);
    1123             :   else
    1124             : #endif /*HAVE_LONG_DOUBLE*/
    1125          78 :     sprintf (numbuf, p, afloat);
    1126             :   p = numbuf;
    1127          84 :   n = strlen (numbuf);
    1128          84 :   pend = p + n;
    1129             : 
    1130          84 :   if (*p =='-')
    1131             :     {
    1132          32 :       signchar = '-';
    1133             :       p++;
    1134          32 :       n--;
    1135             :     }
    1136          52 :   else if ((arg->flags & FLAG_PLUS_SIGN))
    1137           0 :     signchar = '+';
    1138          52 :   else if ((arg->flags & FLAG_SPACE_PLUS))
    1139           0 :     signchar = ' ';
    1140             : 
    1141          84 :   n_extra = !!signchar;
    1142             : 
    1143          84 :   if (!(arg->flags & FLAG_LEFT_JUST)
    1144          56 :       && arg->width >= 0 && arg->width - n_extra > n)
    1145             :     {
    1146          20 :       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
    1147          20 :       if (rc)
    1148             :         return rc;
    1149             :     }
    1150             : 
    1151          84 :   if (signchar)
    1152             :     {
    1153          32 :       rc = outfnc (outfncarg, &signchar, 1);
    1154          32 :       if (rc)
    1155             :         return rc;
    1156          32 :       *nbytes += 1;
    1157             :     }
    1158             : 
    1159          84 :   rc = outfnc (outfncarg, p, pend - p);
    1160          84 :   if (rc)
    1161             :     return rc;
    1162          84 :   *nbytes += pend - p;
    1163             : 
    1164          84 :   if ((arg->flags & FLAG_LEFT_JUST)
    1165          28 :       && arg->width >= 0 && arg->width - n_extra > n)
    1166             :     {
    1167          24 :       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
    1168          24 :       if (rc)
    1169             :         return rc;
    1170             :     }
    1171             : 
    1172             :   return 0;
    1173             : }
    1174             : 
    1175             : 
    1176             : /* "c" formatting.  */
    1177             : static int
    1178             : pr_char (estream_printf_out_t outfnc, void *outfncarg,
    1179             :             argspec_t arg, value_t value, size_t *nbytes)
    1180             : {
    1181             :   int rc;
    1182             :   char buf[1];
    1183             : 
    1184           0 :   if (arg->vt != VALTYPE_INT)
    1185             :     return -1;
    1186           0 :   buf[0] = (unsigned int)value.a_int;
    1187           0 :   rc = outfnc (outfncarg, buf, 1);
    1188           0 :   if(rc)
    1189             :     return rc;
    1190           0 :   *nbytes += 1;
    1191             : 
    1192             :   return 0;
    1193             : }
    1194             : 
    1195             : 
    1196             : /* "s" formatting.  */
    1197             : static int
    1198          40 : pr_string (estream_printf_out_t outfnc, void *outfncarg,
    1199             :             argspec_t arg, value_t value, size_t *nbytes)
    1200             : {
    1201             :   int rc;
    1202             :   size_t n;
    1203             :   const char *string, *s;
    1204             : 
    1205          40 :   if (arg->vt != VALTYPE_STRING)
    1206             :     return -1;
    1207          40 :   string = value.a_string;
    1208          40 :   if (!string)
    1209             :     string = "(null)";
    1210          40 :   if (arg->precision >= 0)
    1211             :     {
    1212             :       /* Test for nul after N so that we can pass a non-nul terminated
    1213             :          string.  */
    1214         410 :       for (n=0,s=string; n < arg->precision && *s; s++)
    1215         410 :         n++;
    1216             :     }
    1217             :   else
    1218          28 :     n = strlen (string);
    1219             : 
    1220          40 :   if (!(arg->flags & FLAG_LEFT_JUST)
    1221          38 :       && arg->width >= 0 && arg->width > n )
    1222             :     {
    1223           9 :       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
    1224           9 :       if (rc)
    1225             :         return rc;
    1226             :     }
    1227             : 
    1228          40 :   rc = outfnc (outfncarg, string, n);
    1229          40 :   if (rc)
    1230             :     return rc;
    1231          40 :   *nbytes += n;
    1232             : 
    1233          40 :   if ((arg->flags & FLAG_LEFT_JUST)
    1234           2 :       && arg->width >= 0 && arg->width > n)
    1235             :     {
    1236           2 :       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
    1237           2 :       if (rc)
    1238             :         return rc;
    1239             :     }
    1240             : 
    1241             :   return 0;
    1242             : }
    1243             : 
    1244             : 
    1245             : /* "p" formatting.  */
    1246             : static int
    1247           0 : pr_pointer (estream_printf_out_t outfnc, void *outfncarg,
    1248             :             argspec_t arg, value_t value, size_t *nbytes)
    1249             : {
    1250             :   int rc;
    1251             : #if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P)
    1252             :   unsigned long long aulong;
    1253             : #else
    1254             :   unsigned long aulong;
    1255             : #endif
    1256             :   char numbuf[100];
    1257             :   char *p, *pend;
    1258             : 
    1259           0 :   if (arg->vt != VALTYPE_POINTER)
    1260             :     return -1;
    1261             :   /* We assume that a pointer can be converted to an unsigned long.
    1262             :      That is not correct for a 64 bit Windows, but then we assume that
    1263             :      long long is supported and usable for storing a pointer.  */
    1264             : #if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P)
    1265             :   aulong = (unsigned long long)value.a_void_ptr;
    1266             : #else
    1267           0 :   aulong = (unsigned long)value.a_void_ptr;
    1268             : #endif
    1269             : 
    1270             :   p = pend = numbuf + DIM(numbuf);
    1271             :   do
    1272             :     {
    1273           0 :       *--p = "0123456789abcdefx"[(aulong % 16)];
    1274           0 :       aulong /= 16;
    1275             :     }
    1276           0 :   while (aulong);
    1277           0 :   while ((pend-p) < 2*sizeof (aulong))
    1278           0 :     *--p = '0';
    1279           0 :   *--p = 'x';
    1280           0 :   *--p = '0';
    1281             : 
    1282           0 :   rc = outfnc (outfncarg, p, pend - p);
    1283           0 :   if (rc)
    1284             :     return rc;
    1285           0 :   *nbytes += pend - p;
    1286             : 
    1287             :   return 0;
    1288             : }
    1289             : 
    1290             : /* "n" pesudo format operation.  */
    1291             : static int
    1292           0 : pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg,
    1293             :                  argspec_t arg, value_t value, size_t *nbytes)
    1294             : {
    1295             :   (void)outfnc;
    1296             :   (void)outfncarg;
    1297             : 
    1298           0 :   switch (arg->vt)
    1299             :     {
    1300             :     case VALTYPE_SCHAR_PTR:
    1301           0 :       *value.a_schar_ptr = (signed char)(unsigned int)(*nbytes);
    1302             :       break;
    1303             :     case VALTYPE_SHORT_PTR:
    1304           0 :       *value.a_short_ptr = (short)(unsigned int)(*nbytes);
    1305             :       break;
    1306             :     case VALTYPE_LONG_PTR:
    1307           0 :       *value.a_long_ptr = (long)(*nbytes);
    1308             :       break;
    1309             : #ifdef HAVE_LONG_LONG_INT
    1310             :     case VALTYPE_LONGLONG_PTR:
    1311           0 :       *value.a_longlong_ptr = (long long)(*nbytes);
    1312             :       break;
    1313             : #endif
    1314             : #ifdef HAVE_INTMAX_T
    1315             :     case VALTYPE_INTMAX_PTR:
    1316           0 :       *value.a_intmax_ptr = (intmax_t)(*nbytes);
    1317             :       break;
    1318             : #endif
    1319             :     case VALTYPE_SIZE_PTR:
    1320           0 :       *value.a_size_ptr = (*nbytes);
    1321             :       break;
    1322             : #ifdef HAVE_PTRDIFF_T
    1323             :     case VALTYPE_PTRDIFF_PTR:
    1324           0 :       *value.a_ptrdiff_ptr = (ptrdiff_t)(*nbytes);
    1325             :       break;
    1326             : #endif
    1327             :     case VALTYPE_INT_PTR:
    1328           0 :       *value.a_int_ptr = (int)(*nbytes);
    1329             :       break;
    1330             :     default:
    1331             :       return -1; /* An unsupported type has been used.  */
    1332             :     }
    1333             : 
    1334             :   return 0;
    1335             : }
    1336             : 
    1337             : 
    1338             : 
    1339             : /* Run the actual formatting.  OUTFNC and OUTFNCARG are the output
    1340             :    functions.  FORMAT is format string ARGSPECS is the parsed format
    1341             :    string, ARGSPECS_LEN the number of items in ARGSPECS.  VALUETABLE
    1342             :    holds the values and may be directly addressed using the position
    1343             :    arguments given by ARGSPECS.  MYERRNO is used for the "%m"
    1344             :    conversion. NBYTES well be updated to reflect the number of bytes
    1345             :    send to the output function. */
    1346             : static int
    1347         335 : do_format (estream_printf_out_t outfnc, void *outfncarg,
    1348             :            const char *format, argspec_t argspecs, size_t argspecs_len,
    1349             :            valueitem_t valuetable, int myerrno, size_t *nbytes)
    1350             : {
    1351             :   int rc = 0;
    1352             :   const char *s;
    1353             :   argspec_t arg = argspecs;
    1354             :   int argidx = 0; /* Only used for assertion.  */
    1355             :   size_t n;
    1356             :   value_t value;
    1357             : 
    1358             :   s = format;
    1359        1220 :   while ( *s )
    1360             :     {
    1361         550 :       if (*s != '%')
    1362             :         {
    1363          93 :           s++;
    1364          93 :           continue;
    1365             :         }
    1366         457 :       if (s != format)
    1367             :         {
    1368          43 :           rc = outfnc (outfncarg, format, (n=s-format));
    1369          43 :           if (rc)
    1370             :             return rc;
    1371          43 :           *nbytes += n;
    1372             :         }
    1373         457 :       if (s[1] == '%')
    1374             :         {
    1375             :           /* Note that this code ignores one trailing percent escape -
    1376             :              this is however okay as the args parser must have
    1377             :              detected this already.  */
    1378           4 :           rc = outfnc (outfncarg, s, 1);
    1379           4 :           if (rc)
    1380             :             return rc;
    1381           4 :           *nbytes += 1;
    1382           4 :           s += 2;
    1383             :           format = s;
    1384           4 :           continue;
    1385             :         }
    1386             : 
    1387             :       /* Save the next start.  */
    1388         453 :       s += arg->length;
    1389             :       format = s;
    1390             : 
    1391         453 :       assert (argidx < argspecs_len);
    1392         453 :       argidx++;
    1393             : 
    1394             :       /* Apply indirect field width and precision values.  */
    1395         453 :       if (arg->width == STAR_FIELD_VALUE)
    1396             :         {
    1397          89 :           assert (valuetable[arg->width_pos-1].vt == VALTYPE_INT);
    1398          89 :           arg->width = valuetable[arg->width_pos-1].value.a_int;
    1399          89 :           if (arg->width < 0)
    1400             :             {
    1401          42 :               arg->width = -arg->width;
    1402          42 :               arg->flags |= FLAG_LEFT_JUST;
    1403             :             }
    1404             :         }
    1405         453 :       if (arg->precision == STAR_FIELD_VALUE)
    1406             :         {
    1407          84 :           assert (valuetable[arg->precision_pos-1].vt == VALTYPE_INT);
    1408          84 :           arg->precision = valuetable[arg->precision_pos-1].value.a_int;
    1409          84 :           if (arg->precision < 0)
    1410          42 :             arg->precision = NO_FIELD_VALUE;
    1411             :         }
    1412             : 
    1413         453 :       if (arg->arg_pos == -1 && arg->conspec == CONSPEC_STRERROR)
    1414           6 :         value.a_string = strerror (myerrno);
    1415             :       else
    1416             :         {
    1417         447 :           assert (arg->vt == valuetable[arg->arg_pos-1].vt);
    1418         447 :           value = valuetable[arg->arg_pos-1].value;
    1419             :         }
    1420             : 
    1421         453 :       switch (arg->conspec)
    1422             :         {
    1423           0 :         case CONSPEC_UNKNOWN: assert (!"bug"); break;
    1424             : 
    1425             :         case CONSPEC_DECIMAL:
    1426             :         case CONSPEC_UNSIGNED:
    1427             :         case CONSPEC_OCTAL:
    1428             :         case CONSPEC_HEX:
    1429             :         case CONSPEC_HEX_UP:
    1430         329 :           rc = pr_integer (outfnc, outfncarg, arg, value, nbytes);
    1431         329 :           break;
    1432             :         case CONSPEC_FLOAT:
    1433             :         case CONSPEC_FLOAT_UP:
    1434             :         case CONSPEC_EXP:
    1435             :         case CONSPEC_EXP_UP:
    1436             :         case CONSPEC_F_OR_G:
    1437             :         case CONSPEC_F_OR_G_UP:
    1438             :         case CONSPEC_HEX_EXP:
    1439             :         case CONSPEC_HEX_EXP_UP:
    1440          84 :           rc = pr_float (outfnc, outfncarg, arg, value, nbytes);
    1441          84 :           break;
    1442             :         case CONSPEC_CHAR:
    1443             :           rc = pr_char (outfnc, outfncarg, arg, value, nbytes);
    1444           0 :           break;
    1445             :         case CONSPEC_STRING:
    1446             :         case CONSPEC_STRERROR:
    1447          40 :           rc = pr_string (outfnc, outfncarg, arg, value, nbytes);
    1448          40 :           break;
    1449             :         case CONSPEC_POINTER:
    1450           0 :           rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes);
    1451           0 :           break;
    1452             :         case CONSPEC_BYTES_SO_FAR:
    1453           0 :           rc = pr_bytes_so_far (outfnc, outfncarg, arg, value, nbytes);
    1454           0 :           break;
    1455             :         }
    1456         453 :       if (rc)
    1457             :         return rc;
    1458         453 :       arg++;
    1459             :     }
    1460             : 
    1461             :   /* Print out any trailing stuff. */
    1462         335 :   n = s - format;
    1463         335 :   rc = n? outfnc (outfncarg, format, n) : 0;
    1464         335 :   if (!rc)
    1465         335 :     *nbytes += n;
    1466             : 
    1467             :   return rc;
    1468             : }
    1469             : 
    1470             : 
    1471             : 
    1472             : 
    1473             : /* The versatile printf formatting routine.  It expects a callback
    1474             :    function OUTFNC and an opaque argument OUTFNCARG used for actual
    1475             :    output of the formatted stuff.  FORMAT is the format specification
    1476             :    and VAARGS a variable argumemt list matching the arguments of
    1477             :    FORMAT.  */
    1478             : int
    1479         335 : _gpgrt_estream_format (estream_printf_out_t outfnc,
    1480             :                        void *outfncarg,
    1481             :                        const char *format, va_list vaargs)
    1482             : {
    1483             :   /* Buffer to hold the argspecs and a pointer to it.*/
    1484             :   struct argspec_s argspecs_buffer[DEFAULT_MAX_ARGSPECS];
    1485         335 :   argspec_t argspecs = argspecs_buffer;
    1486             :   size_t argspecs_len;  /* Number of specifications in ARGSPECS.  */
    1487             : 
    1488             :   /* Buffer to hold the description for the values.  */
    1489             :   struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES];
    1490             :   valueitem_t valuetable = valuetable_buffer;
    1491             : 
    1492             :   int rc;     /* Return code. */
    1493             :   size_t argidx; /* Used to index the argspecs array.  */
    1494             :   size_t validx; /* Used to index the valuetable.  */
    1495             :   int max_pos;/* Highest argument position.  */
    1496             : 
    1497         335 :   size_t nbytes = 0; /* Keep track of the number of bytes passed to
    1498             :                         the output function.  */
    1499             : 
    1500         335 :   int myerrno = errno; /* Save the errno for use with "%m". */
    1501             : 
    1502             : 
    1503             :   /* Parse the arguments to come up with descriptive list.  We can't
    1504             :      do this on the fly because we need to support positional
    1505             :      arguments. */
    1506         335 :   rc = parse_format (format, &argspecs, DIM(argspecs_buffer), &argspecs_len);
    1507         335 :   if (rc)
    1508             :     goto leave;
    1509             : 
    1510             :   /* Check that all ARG_POS fields are set.  */
    1511         453 :   for (argidx=0,max_pos=0; argidx < argspecs_len; argidx++)
    1512             :     {
    1513         453 :       if (argspecs[argidx].arg_pos != -1
    1514         447 :           && argspecs[argidx].arg_pos > max_pos)
    1515             :         max_pos = argspecs[argidx].arg_pos;
    1516         453 :       if (argspecs[argidx].width_pos > max_pos)
    1517             :         max_pos = argspecs[argidx].width_pos;
    1518         453 :       if (argspecs[argidx].precision_pos > max_pos)
    1519             :         max_pos = argspecs[argidx].precision_pos;
    1520             :     }
    1521         335 :   if (!max_pos)
    1522             :     {
    1523             :       /* Fill in all the positions.  */
    1524         447 :       for (argidx=0; argidx < argspecs_len; argidx++)
    1525             :         {
    1526         447 :           if (argspecs[argidx].width == STAR_FIELD_VALUE)
    1527          89 :             argspecs[argidx].width_pos = ++max_pos;
    1528         447 :           if (argspecs[argidx].precision == STAR_FIELD_VALUE)
    1529          84 :             argspecs[argidx].precision_pos = ++max_pos;
    1530         447 :           if (argspecs[argidx].arg_pos != -1 )
    1531         443 :             argspecs[argidx].arg_pos = ++max_pos;
    1532             :         }
    1533             :     }
    1534             :   else
    1535             :     {
    1536             :       /* Check that they are all filled.   More test are done later.  */
    1537           6 :       for (argidx=0; argidx < argspecs_len; argidx++)
    1538             :         {
    1539           6 :           if (!argspecs[argidx].arg_pos
    1540           6 :               || (argspecs[argidx].width == STAR_FIELD_VALUE
    1541           0 :                   && !argspecs[argidx].width_pos)
    1542           6 :               || (argspecs[argidx].precision == STAR_FIELD_VALUE
    1543           0 :                   && !argspecs[argidx].precision_pos))
    1544             :             goto leave_einval;
    1545             :         }
    1546             :     }
    1547             :   /* Check that there is no overflow in max_pos and that it has a
    1548             :      reasonable length.  There may never be more elements than the
    1549             :      number of characters in FORMAT.  */
    1550         335 :   if (max_pos < 0 || max_pos >= strlen (format))
    1551             :     goto leave_einval;
    1552             : 
    1553             : #ifdef DEBUG
    1554             :     dump_argspecs (argspecs, argspecs_len);
    1555             : #endif
    1556             : 
    1557             :   /* Allocate a table to hold the values.  If it is small enough we
    1558             :      use a stack allocated buffer.  */
    1559         335 :   if (max_pos > DIM(valuetable_buffer))
    1560             :     {
    1561           0 :       valuetable = calloc (max_pos, sizeof *valuetable);
    1562           0 :       if (!valuetable)
    1563             :         goto leave_error;
    1564             :     }
    1565             :   else
    1566             :     {
    1567        2680 :       for (validx=0; validx < DIM(valuetable_buffer); validx++)
    1568        2680 :         valuetable[validx].vt = VALTYPE_UNSUPPORTED;
    1569             :     }
    1570         788 :   for (argidx=0; argidx < argspecs_len; argidx++)
    1571             :     {
    1572         453 :       if (argspecs[argidx].arg_pos != - 1)
    1573             :         {
    1574         447 :           validx = argspecs[argidx].arg_pos - 1;
    1575         447 :           if (valuetable[validx].vt)
    1576             :             goto leave_einval; /* Already defined. */
    1577         447 :           valuetable[validx].vt = argspecs[argidx].vt;
    1578             :         }
    1579         453 :       if (argspecs[argidx].width == STAR_FIELD_VALUE)
    1580             :         {
    1581          89 :           validx = argspecs[argidx].width_pos - 1;
    1582          89 :           if (valuetable[validx].vt)
    1583             :             goto leave_einval; /* Already defined.  */
    1584          89 :           valuetable[validx].vt = VALTYPE_INT;
    1585             :         }
    1586         453 :       if (argspecs[argidx].precision == STAR_FIELD_VALUE)
    1587             :         {
    1588          84 :           validx = argspecs[argidx].precision_pos - 1;
    1589          84 :           if (valuetable[validx].vt)
    1590             :             goto leave_einval; /* Already defined.  */
    1591          84 :           valuetable[validx].vt = VALTYPE_INT;
    1592             :         }
    1593             :     }
    1594             : 
    1595             :   /* Read all the arguments.  This will error out for unsupported
    1596             :      types and for not given positional arguments. */
    1597         335 :   rc = read_values (valuetable, max_pos, vaargs);
    1598         335 :   if (rc)
    1599             :     goto leave_einval;
    1600             : 
    1601             : /*   for (validx=0; validx < max_pos; validx++) */
    1602             : /*     fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */
    1603             : 
    1604             :   /* Everything has been collected, go ahead with the formatting.  */
    1605         335 :   rc = do_format (outfnc, outfncarg, format,
    1606             :                   argspecs, argspecs_len, valuetable, myerrno, &nbytes);
    1607             : 
    1608         335 :   goto leave;
    1609             : 
    1610             :  leave_einval:
    1611           0 :   _set_errno (EINVAL);
    1612             :  leave_error:
    1613             :   rc = -1;
    1614             :  leave:
    1615         335 :   if (valuetable != valuetable_buffer)
    1616           0 :     free (valuetable);
    1617         335 :   if (argspecs != argspecs_buffer)
    1618          21 :     free (argspecs);
    1619         335 :   return rc;
    1620             : }
    1621             : 
    1622             : 
    1623             : 
    1624             : 
    1625             : /* A simple output handler utilizing stdio.  */
    1626             : static int
    1627           0 : plain_stdio_out (void *outfncarg, const char *buf, size_t buflen)
    1628             : {
    1629             :   FILE *fp = (FILE*)outfncarg;
    1630             : 
    1631           0 :   if ( fwrite (buf, buflen, 1, fp) != 1 )
    1632             :     return -1;
    1633           0 :   return 0;
    1634             : }
    1635             : 
    1636             : 
    1637             : /* A replacement for printf.  */
    1638             : int
    1639           0 : _gpgrt_estream_printf (const char *format, ...)
    1640             : {
    1641             :   int rc;
    1642             :   va_list arg_ptr;
    1643             : 
    1644           0 :   va_start (arg_ptr, format);
    1645           0 :   rc = _gpgrt_estream_format (plain_stdio_out, stderr, format, arg_ptr);
    1646           0 :   va_end (arg_ptr);
    1647             : 
    1648           0 :   return rc;
    1649             : }
    1650             : 
    1651             : /* A replacement for fprintf.  */
    1652             : int
    1653           0 : _gpgrt_estream_fprintf (FILE *fp, const char *format, ...)
    1654             : {
    1655             :   int rc;
    1656             :   va_list arg_ptr;
    1657             : 
    1658           0 :   va_start (arg_ptr, format);
    1659           0 :   rc = _gpgrt_estream_format (plain_stdio_out, fp, format, arg_ptr);
    1660           0 :   va_end (arg_ptr);
    1661             : 
    1662           0 :   return rc;
    1663             : }
    1664             : 
    1665             : /* A replacement for vfprintf.  */
    1666             : int
    1667           0 : _gpgrt_estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
    1668             : {
    1669           0 :   return _gpgrt_estream_format (plain_stdio_out, fp, format, arg_ptr);
    1670             : }
    1671             : 
    1672             : 
    1673             : 
    1674             : /* Communication object used between estream_snprintf and
    1675             :    fixed_buffer_out.  */
    1676             : struct fixed_buffer_parm_s
    1677             : {
    1678             :   size_t size;    /* Size of the buffer.  */
    1679             :   size_t count;   /* Number of bytes requested for output.  */
    1680             :   size_t used;    /* Used size of the buffer.  */
    1681             :   char *buffer;   /* Provided buffer.  */
    1682             : };
    1683             : 
    1684             : /* A simple malloced buffer output handler.  */
    1685             : static int
    1686         246 : fixed_buffer_out (void *outfncarg, const char *buf, size_t buflen)
    1687             : {
    1688             :   struct fixed_buffer_parm_s *parm = outfncarg;
    1689             : 
    1690         246 :   parm->count += buflen;
    1691             : 
    1692         246 :   if (!parm->buffer)
    1693             :     ;
    1694         232 :   else if (parm->used + buflen < parm->size)
    1695             :     {
    1696             :       /* Handle the common case that everything fits into the buffer
    1697             :          separately.  */
    1698         117 :       memcpy (parm->buffer + parm->used, buf, buflen);
    1699         117 :       parm->used += buflen;
    1700             :     }
    1701             :   else
    1702             :     {
    1703             :       /* The slow version of above.  */
    1704          65 :       for ( ;buflen && parm->used < parm->size; buflen--)
    1705          65 :         parm->buffer[parm->used++] = *buf++;
    1706             :     }
    1707             : 
    1708         246 :   return 0;
    1709             : }
    1710             : 
    1711             : 
    1712             : /* A replacement for vsnprintf. */
    1713             : int
    1714          26 : _gpgrt_estream_vsnprintf (char *buf, size_t bufsize,
    1715             :                    const char *format, va_list arg_ptr)
    1716             : {
    1717             :   struct fixed_buffer_parm_s parm;
    1718             :   int rc;
    1719             : 
    1720          26 :   parm.size = bufsize;
    1721          26 :   parm.count = 0;
    1722          26 :   parm.used = 0;
    1723          26 :   parm.buffer = bufsize?buf:NULL;
    1724          26 :   rc = _gpgrt_estream_format (fixed_buffer_out, &parm, format, arg_ptr);
    1725          26 :   if (!rc)
    1726          26 :     rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul.  */
    1727          26 :   if (rc == -1)
    1728             :     return -1;
    1729          26 :   if (bufsize && buf && parm.size && parm.count >= parm.size)
    1730          19 :     buf[parm.size-1] = 0;
    1731             : 
    1732          26 :   parm.count--; /* Do not count the trailing nul.  */
    1733          26 :   return (int)parm.count; /* Return number of bytes which would have
    1734             :                              been written.  */
    1735             : }
    1736             : 
    1737             : /* A replacement for snprintf.  */
    1738             : int
    1739           0 : _gpgrt_estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
    1740             : {
    1741             :   int rc;
    1742             :   va_list arg_ptr;
    1743             : 
    1744           0 :   va_start (arg_ptr, format);
    1745           0 :   rc = _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr);
    1746           0 :   va_end (arg_ptr);
    1747             : 
    1748           0 :   return rc;
    1749             : }
    1750             : 
    1751             : 
    1752             : 
    1753             : /* Communication object used between estream_asprintf and
    1754             :    dynamic_buffer_out.  */
    1755             : struct dynamic_buffer_parm_s
    1756             : {
    1757             :   int error_flag; /* Internal helper.  */
    1758             :   size_t alloced; /* Allocated size of the buffer.  */
    1759             :   size_t used;    /* Used size of the buffer.  */
    1760             :   char *buffer;   /* Malloced buffer.  */
    1761             : };
    1762             : 
    1763             : /* A simple malloced buffer output handler.  */
    1764             : static int
    1765        1006 : dynamic_buffer_out (void *outfncarg, const char *buf, size_t buflen)
    1766             : {
    1767             :   struct dynamic_buffer_parm_s *parm = outfncarg;
    1768             : 
    1769        1006 :   if (parm->error_flag)
    1770             :     {
    1771             :       /* Just in case some formatting routine did not checked for an
    1772             :          error. */
    1773           0 :       _set_errno (parm->error_flag);
    1774           0 :       return -1;
    1775             :     }
    1776             : 
    1777        1006 :   if (parm->used + buflen >= parm->alloced)
    1778             :     {
    1779             :       char *p;
    1780             : 
    1781           0 :       parm->alloced += buflen + 512;
    1782           0 :       p = my_printf_realloc (parm->buffer, parm->alloced);
    1783           0 :       if (!p)
    1784             :         {
    1785           0 :           parm->error_flag = errno ? errno : ENOMEM;
    1786             :           /* Wipe out what we already accumulated.  This is useful in
    1787             :              case sensitive data is formatted.  */
    1788           0 :           memset (parm->buffer, 0, parm->used);
    1789           0 :           return -1;
    1790             :         }
    1791           0 :       parm->buffer = p;
    1792             :     }
    1793        1006 :   memcpy (parm->buffer + parm->used, buf, buflen);
    1794        1006 :   parm->used += buflen;
    1795             : 
    1796        1006 :   return 0;
    1797             : }
    1798             : 
    1799             : 
    1800             : /* A replacement for vasprintf.  As with the BSD version of vasprintf
    1801             :    -1 will be returned on error and NULL stored at BUFP.  On success
    1802             :    the number of bytes printed will be returned. */
    1803             : int
    1804         306 : _gpgrt_estream_vasprintf (char **bufp, const char *format, va_list arg_ptr)
    1805             : {
    1806             :   struct dynamic_buffer_parm_s parm;
    1807             :   int rc;
    1808             : 
    1809         306 :   parm.error_flag = 0;
    1810         306 :   parm.alloced = 512;
    1811         306 :   parm.used = 0;
    1812         306 :   parm.buffer = my_printf_realloc (NULL, parm.alloced);
    1813         306 :   if (!parm.buffer)
    1814             :     {
    1815           0 :       *bufp = NULL;
    1816           0 :       return -1;
    1817             :     }
    1818             : 
    1819         306 :   rc = _gpgrt_estream_format (dynamic_buffer_out, &parm, format, arg_ptr);
    1820         306 :   if (!rc)
    1821         306 :     rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul.  */
    1822             :   /* Fixme: Should we shrink the resulting buffer?  */
    1823         306 :   if (rc != -1 && parm.error_flag)
    1824             :     {
    1825             :       rc = -1;
    1826           0 :       _set_errno (parm.error_flag);
    1827             :     }
    1828         306 :   if (rc == -1)
    1829             :     {
    1830           0 :       memset (parm.buffer, 0, parm.used);
    1831           0 :       if (parm.buffer)
    1832           0 :         my_printf_realloc (parm.buffer, 0);
    1833           0 :       *bufp = NULL;
    1834           0 :       return -1;
    1835             :     }
    1836         306 :   assert (parm.used);   /* We have at least the terminating Nul.  */
    1837         306 :   *bufp = parm.buffer;
    1838         306 :   return parm.used - 1; /* Do not include that Nul. */
    1839             : }
    1840             : 
    1841             : /* A replacement for asprintf.  As with the BSD of asprintf version -1
    1842             :    will be returned on error and NULL stored at BUFP.  On success the
    1843             :    number of bytes printed will be returned. */
    1844             : int
    1845           0 : _gpgrt_estream_asprintf (char **bufp, const char *format, ...)
    1846             : {
    1847             :   int rc;
    1848             :   va_list arg_ptr;
    1849             : 
    1850           0 :   va_start (arg_ptr, format);
    1851           0 :   rc = _gpgrt_estream_vasprintf (bufp, format, arg_ptr);
    1852           0 :   va_end (arg_ptr);
    1853             : 
    1854           0 :   return rc;
    1855             : }
    1856             : 
    1857             : /* A variant of asprintf.  The function returns the allocated buffer
    1858             :    or NULL on error; ERRNO is set in the error case.  The caller
    1859             :    should use es_free to release the buffer.  This function actually
    1860             :    belongs into estream-printf but we put it here as a convenience
    1861             :    and because es_free is required anyway.  */
    1862             : char *
    1863           0 : _gpgrt_estream_bsprintf (const char *format, ...)
    1864             : {
    1865             :   int rc;
    1866             :   va_list ap;
    1867             :   char *buf;
    1868             : 
    1869           0 :   va_start (ap, format);
    1870           0 :   rc = _gpgrt_estream_vasprintf (&buf, format, ap);
    1871           0 :   va_end (ap);
    1872           0 :   if (rc < 0)
    1873             :     return NULL;
    1874           0 :   return buf;
    1875             : }

Generated by: LCOV version 1.12