Coverage Report

Created: 2024-11-21 07:03

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