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