diff options
author | Werner Koch <[email protected]> | 2014-08-26 15:47:22 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2014-08-26 15:47:54 +0000 |
commit | 519305feb888b529c005b40445d041a088a2f8fc (patch) | |
tree | 74994a5b568e059982ca83a0daa8b7d96035355d /common/estream-printf.c | |
parent | gpg: Allow for positional parameters in the passphrase prompt. (diff) | |
download | gnupg-519305feb888b529c005b40445d041a088a2f8fc.tar.gz gnupg-519305feb888b529c005b40445d041a088a2f8fc.zip |
Switch to the libgpg-error provided estream.
* configure.ac (NEED_GPG_ERROR_VERSION): Reguire 1.14.
(GPGRT_ENABLE_ES_MACROS): Define.
(estream_INIT): Remove.
* m4/estream.m4: Remove.
* common/estream-printf.c, common/estream-printf.h: Remove.
* common/estream.c, common/estream.h: Remove.
* common/init.c (_init_common_subsystems): Call gpgrt initialization.
Diffstat (limited to '')
-rw-r--r-- | common/estream-printf.c | 1855 |
1 files changed, 0 insertions, 1855 deletions
diff --git a/common/estream-printf.c b/common/estream-printf.c deleted file mode 100644 index 83336c8fe..000000000 --- a/common/estream-printf.c +++ /dev/null @@ -1,1855 +0,0 @@ -/* estream-printf.c - Versatile mostly C-99 compliant printf formatting - * Copyright (C) 2007, 2008, 2009, 2010, 2012 g10 Code GmbH - * - * This file is part of Libestream. - * - * Libestream is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libestream is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Libestream; if not, see <http://www.gnu.org/licenses/>. - * - * ALTERNATIVELY, Libestream may be distributed under the terms of the - * following license, in which case the provisions of this license are - * required INSTEAD OF the GNU General Public License. If you wish to - * allow use of your version of this file only under the terms of the - * GNU General Public License, and not to allow others to use your - * version of this file under the terms of the following license, - * indicate your decision by deleting this paragraph and the license - * below. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Required autoconf tests: - - AC_TYPE_LONG_LONG_INT defines HAVE_LONG_LONG_INT - AC_TYPE_LONG_DOUBLE defines HAVE_LONG_DOUBLE - AC_TYPE_INTMAX_T defines HAVE_INTMAX_T - AC_TYPE_UINTMAX_T defines HAVE_UINTMAX_T - AC_CHECK_TYPES([ptrdiff_t]) defines HAVE_PTRDIFF_T - AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG - AC_CHECK_SIZEOF([void *]) defines SIZEOF_VOID_P - HAVE_LANGINFO_THOUSANDS_SEP - - Note that the file estream.m4 provides the autoconf macro - ESTREAM_PRINTF_INIT which runs all required checks. - See estream-printf.h for ways to tune this code. - - Missing stuff: wchar and wint_t - thousands_sep in pr_float. - -*/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM) -# define HAVE_W32_SYSTEM 1 -# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM) -# define HAVE_W32CE_SYSTEM -# endif -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <errno.h> -#include <stddef.h> -#include <assert.h> -#if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T) -# ifdef HAVE_STDINT_H -# include <stdint.h> -# endif -#endif -#ifdef HAVE_LANGINFO_THOUSANDS_SEP -#include <langinfo.h> -#endif -#ifdef HAVE_W32CE_SYSTEM -#include <gpg-error.h> /* ERRNO replacement. */ -#endif -#ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE -# include _ESTREAM_PRINTF_EXTRA_INCLUDE -#endif -#include "estream-printf.h" - -/* #define DEBUG 1 */ - - -/* Allow redefinition of asprintf used realloc function. */ -#if defined(_ESTREAM_PRINTF_REALLOC) -#define my_printf_realloc(a,b) _ESTREAM_PRINTF_REALLOC((a),(b)) -#else -#define my_printf_realloc(a,b) fixed_realloc((a),(b)) -#endif - -/* A wrapper to set ERRNO. */ -#ifdef HAVE_W32CE_SYSTEM -# define _set_errno(a) gpg_err_set_errno ((a)) -#else -# define _set_errno(a) do { errno = (a); } while (0) -#endif - - -/* Calculate array dimension. */ -#ifndef DIM -#define DIM(array) (sizeof (array) / sizeof (*array)) -#endif - - -/* We allow for that many args without requiring malloced memory. */ -#define DEFAULT_MAX_ARGSPECS 5 - -/* We allow for that many values without requiring malloced memory. */ -#define DEFAULT_MAX_VALUES 8 - -/* We allocate this many new array argspec elements each time. */ -#define ARGSPECS_BUMP_VALUE 10 - -/* Special values for the field width and the precision. */ -#define NO_FIELD_VALUE (-1) -#define STAR_FIELD_VALUE (-2) - -/* Bit valuues used for the conversion flags. */ -#define FLAG_GROUPING 1 -#define FLAG_LEFT_JUST 2 -#define FLAG_PLUS_SIGN 4 -#define FLAG_SPACE_PLUS 8 -#define FLAG_ALT_CONV 16 -#define FLAG_ZERO_PAD 32 - -/* Constants used the length modifiers. */ -typedef enum - { - LENMOD_NONE = 0, - LENMOD_CHAR, /* "hh" */ - LENMOD_SHORT, /* "h" */ - LENMOD_LONG, /* "l" */ - LENMOD_LONGLONG, /* "ll" */ - LENMOD_INTMAX, /* "j" */ - LENMOD_SIZET, /* "z" */ - LENMOD_PTRDIFF, /* "t" */ - LENMOD_LONGDBL /* "L" */ - } lenmod_t; - -/* All the conversion specifiers. */ -typedef enum - { - CONSPEC_UNKNOWN = 0, - CONSPEC_DECIMAL, - CONSPEC_OCTAL, - CONSPEC_UNSIGNED, - CONSPEC_HEX, - CONSPEC_HEX_UP, - CONSPEC_FLOAT, - CONSPEC_FLOAT_UP, - CONSPEC_EXP, - CONSPEC_EXP_UP, - CONSPEC_F_OR_G, - CONSPEC_F_OR_G_UP, - CONSPEC_HEX_EXP, - CONSPEC_HEX_EXP_UP, - CONSPEC_CHAR, - CONSPEC_STRING, - CONSPEC_POINTER, - CONSPEC_STRERROR, - CONSPEC_BYTES_SO_FAR - } conspec_t; - - -/* Constants describing all the suppoorted types. Note that we list - all the types we know about even if certain types are not available - on this system. */ -typedef enum - { - VALTYPE_UNSUPPORTED = 0, /* Artificial type for error detection. */ - VALTYPE_CHAR, - VALTYPE_SCHAR, - VALTYPE_UCHAR, - VALTYPE_SHORT, - VALTYPE_USHORT, - VALTYPE_INT, - VALTYPE_UINT, - VALTYPE_LONG, - VALTYPE_ULONG, - VALTYPE_LONGLONG, - VALTYPE_ULONGLONG, - VALTYPE_DOUBLE, - VALTYPE_LONGDOUBLE, - VALTYPE_STRING, - VALTYPE_INTMAX, - VALTYPE_UINTMAX, - VALTYPE_SIZE, - VALTYPE_PTRDIFF, - VALTYPE_POINTER, - VALTYPE_CHAR_PTR, - VALTYPE_SCHAR_PTR, - VALTYPE_SHORT_PTR, - VALTYPE_INT_PTR, - VALTYPE_LONG_PTR, - VALTYPE_LONGLONG_PTR, - VALTYPE_INTMAX_PTR, - VALTYPE_SIZE_PTR, - VALTYPE_PTRDIFF_PTR - } valtype_t; - - -/* A union used to store the actual values. */ -typedef union -{ - char a_char; - signed char a_schar; - unsigned char a_uchar; - short a_short; - unsigned short a_ushort; - int a_int; - unsigned int a_uint; - long int a_long; - unsigned long int a_ulong; -#ifdef HAVE_LONG_LONG_INT - long long int a_longlong; - unsigned long long int a_ulonglong; -#endif - double a_double; -#ifdef HAVE_LONG_DOUBLE - long double a_longdouble; -#endif - const char *a_string; -#ifdef HAVE_INTMAX_T - intmax_t a_intmax; -#endif -#ifdef HAVE_UINTMAX_T - intmax_t a_uintmax; -#endif - size_t a_size; -#ifdef HAVE_PTRDIFF_T - ptrdiff_t a_ptrdiff; -#endif - void *a_void_ptr; - char *a_char_ptr; - signed char *a_schar_ptr; - short *a_short_ptr; - int *a_int_ptr; - long *a_long_ptr; -#ifdef HAVE_LONG_LONG_INT - long long int *a_longlong_ptr; -#endif -#ifdef HAVE_INTMAX_T - intmax_t *a_intmax_ptr; -#endif - size_t *a_size_ptr; -#ifdef HAVE_PTRDIFF_T - ptrdiff_t *a_ptrdiff_ptr; -#endif -} value_t; - -/* An object used to keep track of a format option and arguments. */ -struct argspec_s -{ - size_t length; /* The length of these args including the percent. */ - unsigned int flags; /* The conversion flags (bits defined by FLAG_foo). */ - int width; /* The field width. */ - int precision; /* The precision. */ - lenmod_t lenmod; /* The length modifier. */ - conspec_t conspec; /* The conversion specifier. */ - int arg_pos; /* The position of the argument. This one may - be -1 to indicate that no value is expected - (e.g. for "%m"). */ - int width_pos; /* The position of the argument for a field - width star's value. 0 for not used. */ - int precision_pos; /* The position of the argument for the a - precision star's value. 0 for not used. */ - valtype_t vt; /* The type of the corresponding argument. */ -}; -typedef struct argspec_s *argspec_t; - -/* An object to build up a table of values and their types. */ -struct valueitem_s -{ - valtype_t vt; /* The type of the value. */ - value_t value; /* The value. */ -}; -typedef struct valueitem_s *valueitem_t; - - -/* Not all systems have a C-90 compliant realloc. To cope with this - we use this simple wrapper. */ -#ifndef _ESTREAM_PRINTF_REALLOC -static void * -fixed_realloc (void *a, size_t n) -{ - if (!a) - return malloc (n); - - if (!n) - { - free (a); - return NULL; - } - - return realloc (a, n); -} -#endif /*!_ESTREAM_PRINTF_REALLOC*/ - - -#ifdef DEBUG -static void -dump_argspecs (argspec_t arg, size_t argcount) -{ - int idx; - - for (idx=0; argcount; argcount--, arg++, idx++) - fprintf (stderr, - "%2d: len=%u flags=%u width=%d prec=%d mod=%d " - "con=%d vt=%d pos=%d-%d-%d\n", - idx, - (unsigned int)arg->length, - arg->flags, - arg->width, - arg->precision, - arg->lenmod, - arg->conspec, - arg->vt, - arg->arg_pos, - arg->width_pos, - arg->precision_pos); -} -#endif /*DEBUG*/ - - -/* Set the vt field for ARG. */ -static void -compute_type (argspec_t arg) -{ - switch (arg->conspec) - { - case CONSPEC_UNKNOWN: - arg->vt = VALTYPE_UNSUPPORTED; - break; - - case CONSPEC_DECIMAL: - switch (arg->lenmod) - { - case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break; - case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break; - case LENMOD_LONG: arg->vt = VALTYPE_LONG; break; - case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break; - case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break; - case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break; - case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break; - default: arg->vt = VALTYPE_INT; break; - } - break; - - case CONSPEC_OCTAL: - case CONSPEC_UNSIGNED: - case CONSPEC_HEX: - case CONSPEC_HEX_UP: - switch (arg->lenmod) - { - case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break; - case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break; - case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break; - case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break; - case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break; - case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break; - case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break; - default: arg->vt = VALTYPE_UINT; break; - } - break; - - case CONSPEC_FLOAT: - case CONSPEC_FLOAT_UP: - case CONSPEC_EXP: - case CONSPEC_EXP_UP: - case CONSPEC_F_OR_G: - case CONSPEC_F_OR_G_UP: - case CONSPEC_HEX_EXP: - case CONSPEC_HEX_EXP_UP: - switch (arg->lenmod) - { - case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break; - case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break; - default: arg->vt = VALTYPE_DOUBLE; break; - } - break; - - case CONSPEC_CHAR: - arg->vt = VALTYPE_INT; - break; - - case CONSPEC_STRING: - arg->vt = VALTYPE_STRING; - break; - - case CONSPEC_POINTER: - arg->vt = VALTYPE_POINTER; - break; - - case CONSPEC_STRERROR: - arg->vt = VALTYPE_STRING; - break; - - case CONSPEC_BYTES_SO_FAR: - switch (arg->lenmod) - { - case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break; - case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break; - case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break; - case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break; - case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break; - case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break; - case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break; - default: arg->vt = VALTYPE_INT_PTR; break; - } - break; - - } -} - - - -/* Parse the FORMAT string and populate the specification array stored - at the address ARGSPECS_ADDR. The caller has provided enough space - to store up to MAX_ARGSPECS in that buffer. The function may - however ignore the provided buffer and malloc a larger one. On - success the addrrss of that larger buffer will be stored at - ARGSPECS_ADDR. The actual number of specifications will be - returned at R_ARGSPECS_COUNT. */ -static int -parse_format (const char *format, - argspec_t *argspecs_addr, size_t max_argspecs, - size_t *r_argspecs_count) -{ - const char *s; - argspec_t argspecs = *argspecs_addr; - argspec_t arg; - size_t argcount = 0; - - if (!format) - goto leave_einval; - - for (; *format; format++) - { - unsigned int flags; - int width, precision; - lenmod_t lenmod; - conspec_t conspec; - int arg_pos, width_pos, precision_pos; - - if (*format != '%') - continue; - s = ++format; - if (!*s) - goto leave_einval; - if (*s == '%') - continue; /* Just a quoted percent. */ - - /* First check whether there is a positional argument. */ - arg_pos = 0; /* No positional argument given. */ - if (*s >= '1' && *s <= '9') - { - const char *save_s = s; - - arg_pos = (*s++ - '0'); - for (; *s >= '0' && *s <= '9'; s++) - arg_pos = 10*arg_pos + (*s - '0'); - if (arg_pos < 0) - goto leave_einval; /* Overflow during conversion. */ - if (*s == '$') - s++; - else - { - arg_pos = 0; - s = save_s; - } - } - - /* Parse the flags. */ - flags = 0; - for ( ; *s; s++) - { - switch (*s) - { - case '\'': flags |= FLAG_GROUPING; break; - case '-': flags |= FLAG_LEFT_JUST; break; - case '+': flags |= FLAG_PLUS_SIGN; break; - case ' ': flags |= FLAG_SPACE_PLUS; break; - case '#': flags |= FLAG_ALT_CONV; break; - case '0': flags |= FLAG_ZERO_PAD; break; - default: - goto flags_parsed; - } - } - flags_parsed: - - /* Parse the field width. */ - width_pos = 0; - if (*s == '*') - { - width = STAR_FIELD_VALUE; - s++; - /* If we have a positional argument, another one might also - be used to give the position of the star's value. */ - if (arg_pos && *s >= '1' && *s <= '9') - { - width_pos = (*s++ - '0'); - for (; *s >= '0' && *s <= '9'; s++) - width_pos = 10*width_pos + (*s - '0'); - if (width_pos < 1) - goto leave_einval; /* Overflow during conversion. */ - if (*s != '$') - goto leave_einval; /* Not followed by $. */ - s++; - } - } - else if ( *s >= '0' && *s <= '9') - { - width = (*s++ - '0'); - for (; *s >= '0' && *s <= '9'; s++) - { - if (!width && *s == '0') - goto leave_einval; /* Leading zeroes are not allowed. - Fixme: check what other - implementations do. */ - width = 10*width + (*s - '0'); - } - if (width < 0) - goto leave_einval; /* Overflow during conversion. */ - } - else - width = NO_FIELD_VALUE; - - /* Parse the precision. */ - precision_pos = 0; - precision = NO_FIELD_VALUE; - if (*s == '.') - { - int ignore_value = (s[1] == '-'); - - s++; - if (*s == '*') - { - precision = STAR_FIELD_VALUE; - s++; - /* If we have a positional argument, another one might also - be used to give the position of the star's value. */ - if (arg_pos && *s >= '1' && *s <= '9') - { - precision_pos = (*s++ - '0'); - for (; *s >= '0' && *s <= '9'; s++) - precision_pos = 10*precision_pos + (*s - '0'); - if (precision_pos < 1) - goto leave_einval; /* Overflow during conversion. */ - if (*s != '$') - goto leave_einval; /* Not followed by $. */ - s++; - } - } - else if ( *s >= '0' && *s <= '9') - { - precision = (*s++ - '0'); - for (; *s >= '0' && *s <= '9'; s++) - { - if (!precision && *s == '0') - goto leave_einval; /* Leading zeroes are not allowed. - Fixme: check what other - implementations do. */ - precision = 10*precision + (*s - '0'); - } - if (precision < 0) - goto leave_einval; /* Overflow during conversion. */ - } - else - precision = 0; - if (ignore_value) - precision = NO_FIELD_VALUE; - } - - /* Parse the length modifiers. */ - switch (*s) - { - case 'h': - if (s[1] == 'h') - { - lenmod = LENMOD_CHAR; - s++; - } - else - lenmod = LENMOD_SHORT; - s++; - break; - case 'l': - if (s[1] == 'l') - { - lenmod = LENMOD_LONGLONG; - s++; - } - else - lenmod = LENMOD_LONG; - s++; - break; - case 'j': lenmod = LENMOD_INTMAX; s++; break; - case 'z': lenmod = LENMOD_SIZET; s++; break; - case 't': lenmod = LENMOD_PTRDIFF; s++; break; - case 'L': lenmod = LENMOD_LONGDBL; s++; break; - default: lenmod = LENMOD_NONE; break; - } - - /* Parse the conversion specifier. */ - switch (*s) - { - case 'd': - case 'i': conspec = CONSPEC_DECIMAL; break; - case 'o': conspec = CONSPEC_OCTAL; break; - case 'u': conspec = CONSPEC_UNSIGNED; break; - case 'x': conspec = CONSPEC_HEX; break; - case 'X': conspec = CONSPEC_HEX_UP; break; - case 'f': conspec = CONSPEC_FLOAT; break; - case 'F': conspec = CONSPEC_FLOAT_UP; break; - case 'e': conspec = CONSPEC_EXP; break; - case 'E': conspec = CONSPEC_EXP_UP; break; - case 'g': conspec = CONSPEC_F_OR_G; break; - case 'G': conspec = CONSPEC_F_OR_G_UP; break; - case 'a': conspec = CONSPEC_HEX_EXP; break; - case 'A': conspec = CONSPEC_HEX_EXP_UP; break; - case 'c': conspec = CONSPEC_CHAR; break; - case 's': conspec = CONSPEC_STRING; break; - case 'p': conspec = CONSPEC_POINTER; break; - case 'n': conspec = CONSPEC_BYTES_SO_FAR; break; - case 'C': conspec = CONSPEC_CHAR; lenmod = LENMOD_LONG; break; - case 'S': conspec = CONSPEC_STRING; lenmod = LENMOD_LONG; break; - case 'm': conspec = CONSPEC_STRERROR; arg_pos = -1; break; - default: conspec = CONSPEC_UNKNOWN; - } - - /* Save the args. */ - if (argcount >= max_argspecs) - { - /* We either need to allocate a new array instead of the - caller provided one or realloc the array. Instead of - using realloc we allocate a new one and release the - original one then. */ - size_t n, newmax; - argspec_t newarg; - - newmax = max_argspecs + ARGSPECS_BUMP_VALUE; - if (newmax <= max_argspecs) - goto leave_einval; /* Too many arguments. */ - newarg = calloc (newmax, sizeof *newarg); - if (!newarg) - goto leave; - for (n=0; n < argcount; n++) - newarg[n] = argspecs[n]; - if (argspecs != *argspecs_addr) - free (argspecs); - argspecs = newarg; - max_argspecs = newmax; - } - - arg = argspecs + argcount; - arg->length = s - format + 2; - arg->flags = flags; - arg->width = width; - arg->precision = precision; - arg->lenmod = lenmod; - arg->conspec = conspec; - arg->arg_pos = arg_pos; - arg->width_pos = width_pos; - arg->precision_pos = precision_pos; - compute_type (arg); - argcount++; - format = s; - } - - *argspecs_addr = argspecs; - *r_argspecs_count = argcount; - return 0; /* Success. */ - - leave_einval: - _set_errno (EINVAL); - leave: - if (argspecs != *argspecs_addr) - free (argspecs); - *argspecs_addr = NULL; - return -1; -} - - -/* This function reads all the values as specified by VALUETABLE into - VALUETABLE. The values are expected in VAARGS. The function - returns -1 if a specified type is not supported. */ -static int -read_values (valueitem_t valuetable, size_t valuetable_len, va_list vaargs) -{ - int validx; - - for (validx=0; validx < valuetable_len; validx++) - { - value_t *value = &valuetable[validx].value; - valtype_t vt = valuetable[validx].vt; - - switch (vt) - { - case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break; - case VALTYPE_CHAR_PTR: - value->a_char_ptr = va_arg (vaargs, char *); - break; - case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break; - case VALTYPE_SCHAR_PTR: - value->a_schar_ptr = va_arg (vaargs, signed char *); - break; - case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break; - case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break; - case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break; - case VALTYPE_SHORT_PTR: - value->a_short_ptr = va_arg (vaargs, short *); - break; - case VALTYPE_INT: - value->a_int = va_arg (vaargs, int); - break; - case VALTYPE_INT_PTR: - value->a_int_ptr = va_arg (vaargs, int *); - break; - case VALTYPE_UINT: - value->a_uint = va_arg (vaargs, unsigned int); - break; - case VALTYPE_LONG: - value->a_long = va_arg (vaargs, long); - break; - case VALTYPE_ULONG: - value->a_ulong = va_arg (vaargs, unsigned long); - break; - case VALTYPE_LONG_PTR: - value->a_long_ptr = va_arg (vaargs, long *); - break; -#ifdef HAVE_LONG_LONG_INT - case VALTYPE_LONGLONG: - value->a_longlong = va_arg (vaargs, long long int); - break; - case VALTYPE_ULONGLONG: - value->a_ulonglong = va_arg (vaargs, unsigned long long int); - break; - case VALTYPE_LONGLONG_PTR: - value->a_longlong_ptr = va_arg (vaargs, long long *); - break; -#endif - case VALTYPE_DOUBLE: - value->a_double = va_arg (vaargs, double); - break; -#ifdef HAVE_LONG_DOUBLE - case VALTYPE_LONGDOUBLE: - value->a_longdouble = va_arg (vaargs, long double); - break; -#endif - case VALTYPE_STRING: - value->a_string = va_arg (vaargs, const char *); - break; - case VALTYPE_POINTER: - value->a_void_ptr = va_arg (vaargs, void *); - break; -#ifdef HAVE_INTMAX_T - case VALTYPE_INTMAX: - value->a_intmax = va_arg (vaargs, intmax_t); - break; - case VALTYPE_INTMAX_PTR: - value->a_intmax_ptr = va_arg (vaargs, intmax_t *); - break; -#endif -#ifdef HAVE_UINTMAX_T - case VALTYPE_UINTMAX: - value->a_uintmax = va_arg (vaargs, uintmax_t); - break; -#endif - case VALTYPE_SIZE: - value->a_size = va_arg (vaargs, size_t); - break; - case VALTYPE_SIZE_PTR: - value->a_size_ptr = va_arg (vaargs, size_t *); - break; -#ifdef HAVE_PTRDIFF_T - case VALTYPE_PTRDIFF: - value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); - break; - case VALTYPE_PTRDIFF_PTR: - value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *); - break; -#endif - default: /* Unsupported type. */ - return -1; - } - } - return 0; -} - - - -/* Output COUNT padding characters PADCHAR and update NBYTES by the - number of bytes actually written. */ -static int -pad_out (estream_printf_out_t outfnc, void *outfncarg, - int padchar, int count, size_t *nbytes) -{ - char buf[32]; - size_t n; - int rc; - - while (count > 0) - { - n = (count <= sizeof buf)? count : sizeof buf; - memset (buf, padchar, n); - rc = outfnc (outfncarg, buf, n); - if (rc) - return rc; - *nbytes += n; - count -= n; - } - - return 0; -} - - -/* "d,i,o,u,x,X" formatting. OUTFNC and OUTFNCARG describes the - output routine, ARG gives the argument description and VALUE the - actual value (its type is available through arg->vt). */ -static int -pr_integer (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - int rc; -#ifdef HAVE_LONG_LONG_INT - unsigned long long aulong; -#else - unsigned long aulong; -#endif - char numbuf[100]; - char *p, *pend; - size_t n; - char signchar = 0; - int n_prec; /* Number of extra precision digits required. */ - int n_extra; /* Extra number of prefix or sign characters. */ - - if (arg->conspec == CONSPEC_DECIMAL) - { -#ifdef HAVE_LONG_LONG_INT - long long along; -#else - long along; -#endif - - switch (arg->vt) - { - case VALTYPE_SHORT: along = value.a_short; break; - case VALTYPE_INT: along = value.a_int; break; - case VALTYPE_LONG: along = value.a_long; break; -#ifdef HAVE_LONG_LONG_INT - case VALTYPE_LONGLONG: along = value.a_longlong; break; - case VALTYPE_SIZE: along = value.a_size; break; -# ifdef HAVE_INTMAX_T - case VALTYPE_INTMAX: along = value.a_intmax; break; -# endif -# ifdef HAVE_PTRDIFF_T - case VALTYPE_PTRDIFF: along = value.a_ptrdiff; break; -# endif -#endif /*HAVE_LONG_LONG_INT*/ - default: - return -1; - } - if (along < 0) - { - aulong = -along; - signchar = '-'; - } - else - aulong = along; - } - else - { - switch (arg->vt) - { - case VALTYPE_USHORT: aulong = value.a_ushort; break; - case VALTYPE_UINT: aulong = value.a_uint; break; - case VALTYPE_ULONG: aulong = value.a_ulong; break; -#ifdef HAVE_LONG_LONG_INT - case VALTYPE_ULONGLONG: aulong = value.a_ulonglong; break; - case VALTYPE_SIZE: aulong = value.a_size; break; -# ifdef HAVE_UINTMAX_T - case VALTYPE_UINTMAX: aulong = value.a_uintmax; break; -# endif -# ifdef HAVE_PTRDIFF_T - case VALTYPE_PTRDIFF: aulong = value.a_ptrdiff; break; -# endif -#endif /*HAVE_LONG_LONG_INT*/ - default: - return -1; - } - } - - if (signchar == '-') - ; - else if ((arg->flags & FLAG_PLUS_SIGN)) - signchar = '+'; - else if ((arg->flags & FLAG_SPACE_PLUS)) - signchar = ' '; - - n_extra = !!signchar; - - /* We build the string up backwards. */ - p = pend = numbuf + DIM(numbuf); - if ((!aulong && !arg->precision)) - ; - else if (arg->conspec == CONSPEC_DECIMAL - || arg->conspec == CONSPEC_UNSIGNED) - { - int grouping = -1; - const char * grouping_string = -#ifdef HAVE_LANGINFO_THOUSANDS_SEP - nl_langinfo(THOUSANDS_SEP); -#else - "'"; -#endif - - do - { - if ((arg->flags & FLAG_GROUPING) - && (++grouping == 3) && *grouping_string) - { - *--p = *grouping_string; - grouping = 0; - } - *--p = '0' + (aulong % 10); - aulong /= 10; - } - while (aulong); - } - else if (arg->conspec == CONSPEC_OCTAL) - { - do - { - *--p = '0' + (aulong % 8); - aulong /= 8; - } - while (aulong); - if ((arg->flags & FLAG_ALT_CONV) && *p != '0') - *--p = '0'; - } - else /* HEX or HEXUP */ - { - const char *digits = ((arg->conspec == CONSPEC_HEX) - ? "0123456789abcdef" : "0123456789ABCDEF"); - do - { - *--p = digits[(aulong % 16)]; - aulong /= 16; - } - while (aulong); - if ((arg->flags & FLAG_ALT_CONV)) - n_extra += 2; - } - - n = pend - p; - - if ((arg->flags & FLAG_ZERO_PAD) - && arg->precision == NO_FIELD_VALUE && !(arg->flags & FLAG_LEFT_JUST) - && n && arg->width - n_extra > n ) - n_prec = arg->width - n_extra - n; - else if (arg->precision > 0 && arg->precision > n) - n_prec = arg->precision - n; - else - n_prec = 0; - - if (!(arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width - n_extra > n - && arg->width - n_extra - n >= n_prec ) - { - rc = pad_out (outfnc, outfncarg, ' ', - arg->width - n_extra - n - n_prec, nbytes); - if (rc) - return rc; - } - - if (signchar) - { - rc = outfnc (outfncarg, &signchar, 1); - if (rc) - return rc; - *nbytes += 1; - } - - if ((arg->flags & FLAG_ALT_CONV) - && (arg->conspec == CONSPEC_HEX || arg->conspec == CONSPEC_HEX_UP)) - { - rc = outfnc (outfncarg, arg->conspec == CONSPEC_HEX? "0x": "0X", 2); - if (rc) - return rc; - *nbytes += 2; - } - - if (n_prec) - { - rc = pad_out (outfnc, outfncarg, '0', n_prec, nbytes); - if (rc) - return rc; - } - - rc = outfnc (outfncarg, p, pend - p); - if (rc) - return rc; - *nbytes += pend - p; - - if ((arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width - n_extra - n_prec > n) - { - rc = pad_out (outfnc, outfncarg, ' ', - arg->width - n_extra - n_prec - n, nbytes); - if (rc) - return rc; - } - - return 0; -} - - -/* "e,E,f,F,g,G,a,A" formatting. OUTFNC and OUTFNCARG describes the - output routine, ARG gives the argument description and VALUE the - actual value (its type is available through arg->vt). For - portability reasons sprintf is used for the actual formatting. - This is useful because sprint is the only standard function to - convert a floating number into its ascii representation. To avoid - using malloc we just pass the precision to sprintf and do the final - formatting with our own code. */ -static int -pr_float (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - int rc; -#ifdef HAVE_LONG_DOUBLE - long double adblfloat = 0; /* Just to please gcc. */ - int use_dbl = 0; -#endif - double afloat; - char numbuf[350]; - char formatstr[20]; - char *p, *pend; - size_t n; - char signchar = 0; - int n_extra; /* Extra number of prefix or sign characters. */ - - switch (arg->vt) - { - case VALTYPE_DOUBLE: afloat = value.a_double; break; -#ifdef HAVE_LONG_DOUBLE - case VALTYPE_LONGDOUBLE: - afloat = 0; /* Just to please gcc. */ - adblfloat = value.a_longdouble; - use_dbl=1; break; -#endif - default: - return -1; - } - - /* We build the string using sprint. */ - p = formatstr + sizeof formatstr; - *--p = 0; - switch (arg->conspec) - { - case CONSPEC_FLOAT: *--p = 'f'; break; - case CONSPEC_FLOAT_UP: *--p = 'F'; break; - case CONSPEC_EXP: *--p = 'e'; break; - case CONSPEC_EXP_UP: *--p = 'E'; break; - case CONSPEC_F_OR_G: *--p = 'g'; break; - case CONSPEC_F_OR_G_UP: *--p = 'G'; break; - case CONSPEC_HEX_EXP: *--p = 'a'; break; - case CONSPEC_HEX_EXP_UP: *--p = 'A'; break; - default: - return -1; /* Actually a bug. */ - } -#ifdef HAVE_LONG_DOUBLE - if (use_dbl) - *--p = 'L'; -#endif - if (arg->precision != NO_FIELD_VALUE) - { - /* Limit it to a meaningful value so that even a stupid sprintf - won't overflow our buffer. */ - n = arg->precision <= 100? arg->precision : 100; - do - { - *--p = '0' + (n % 10); - n /= 10; - } - while (n); - *--p = '.'; - } - if ((arg->flags & FLAG_ALT_CONV)) - *--p = '#'; - *--p = '%'; -#ifdef HAVE_LONG_DOUBLE - if (use_dbl) - sprintf (numbuf, p, adblfloat); - else -#endif /*HAVE_LONG_DOUBLE*/ - sprintf (numbuf, p, afloat); - p = numbuf; - n = strlen (numbuf); - pend = p + n; - - if (*p =='-') - { - signchar = '-'; - p++; - n--; - } - else if ((arg->flags & FLAG_PLUS_SIGN)) - signchar = '+'; - else if ((arg->flags & FLAG_SPACE_PLUS)) - signchar = ' '; - - n_extra = !!signchar; - - if (!(arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width - n_extra > n) - { - rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes); - if (rc) - return rc; - } - - if (signchar) - { - rc = outfnc (outfncarg, &signchar, 1); - if (rc) - return rc; - *nbytes += 1; - } - - rc = outfnc (outfncarg, p, pend - p); - if (rc) - return rc; - *nbytes += pend - p; - - if ((arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width - n_extra > n) - { - rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes); - if (rc) - return rc; - } - - return 0; -} - - -/* "c" formatting. */ -static int -pr_char (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - int rc; - char buf[1]; - - if (arg->vt != VALTYPE_INT) - return -1; - buf[0] = (unsigned int)value.a_int; - rc = outfnc (outfncarg, buf, 1); - if(rc) - return rc; - *nbytes += 1; - - return 0; -} - - -/* "s" formatting. */ -static int -pr_string (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - int rc; - size_t n; - const char *string, *s; - - if (arg->vt != VALTYPE_STRING) - return -1; - string = value.a_string; - if (!string) - string = "(null)"; - if (arg->precision >= 0) - { - /* Test for nul after N so that we can pass a non-nul terminated - string. */ - for (n=0,s=string; n < arg->precision && *s; s++) - n++; - } - else - n = strlen (string); - - if (!(arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width > n ) - { - rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); - if (rc) - return rc; - } - - rc = outfnc (outfncarg, string, n); - if (rc) - return rc; - *nbytes += n; - - if ((arg->flags & FLAG_LEFT_JUST) - && arg->width >= 0 && arg->width > n) - { - rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); - if (rc) - return rc; - } - - return 0; -} - - -/* "p" formatting. */ -static int -pr_pointer (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - int rc; -#if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P) - unsigned long long aulong; -#else - unsigned long aulong; -#endif - char numbuf[100]; - char *p, *pend; - - if (arg->vt != VALTYPE_POINTER) - return -1; - /* We assume that a pointer can be converted to an unsigned long. - That is not correct for a 64 bit Windows, but then we assume that - long long is supported and usable for storing a pointer. */ -#if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P) - aulong = (unsigned long long)value.a_void_ptr; -#else - aulong = (unsigned long)value.a_void_ptr; -#endif - - p = pend = numbuf + DIM(numbuf); - do - { - *--p = "0123456789abcdefx"[(aulong % 16)]; - aulong /= 16; - } - while (aulong); - while ((pend-p) < 2*sizeof (aulong)) - *--p = '0'; - *--p = 'x'; - *--p = '0'; - - rc = outfnc (outfncarg, p, pend - p); - if (rc) - return rc; - *nbytes += pend - p; - - return 0; -} - -/* "n" pesudo format operation. */ -static int -pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg, - argspec_t arg, value_t value, size_t *nbytes) -{ - (void)outfnc; - (void)outfncarg; - - switch (arg->vt) - { - case VALTYPE_SCHAR_PTR: - *value.a_schar_ptr = (signed char)(unsigned int)(*nbytes); - break; - case VALTYPE_SHORT_PTR: - *value.a_short_ptr = (short)(unsigned int)(*nbytes); - break; - case VALTYPE_LONG_PTR: - *value.a_long_ptr = (long)(*nbytes); - break; -#ifdef HAVE_LONG_LONG_INT - case VALTYPE_LONGLONG_PTR: - *value.a_longlong_ptr = (long long)(*nbytes); - break; -#endif -#ifdef HAVE_INTMAX_T - case VALTYPE_INTMAX_PTR: - *value.a_intmax_ptr = (intmax_t)(*nbytes); - break; -#endif - case VALTYPE_SIZE_PTR: - *value.a_size_ptr = (*nbytes); - break; -#ifdef HAVE_PTRDIFF_T - case VALTYPE_PTRDIFF_PTR: - *value.a_ptrdiff_ptr = (ptrdiff_t)(*nbytes); - break; -#endif - case VALTYPE_INT_PTR: - *value.a_int_ptr = (int)(*nbytes); - break; - default: - return -1; /* An unsupported type has been used. */ - } - - return 0; -} - - - -/* Run the actual formatting. OUTFNC and OUTFNCARG are the output - functions. FORMAT is format string ARGSPECS is the parsed format - string, ARGSPECS_LEN the number of items in ARGSPECS. VALUETABLE - holds the values and may be directly addressed using the position - arguments given by ARGSPECS. MYERRNO is used for the "%m" - conversion. NBYTES well be updated to reflect the number of bytes - send to the output function. */ -static int -do_format (estream_printf_out_t outfnc, void *outfncarg, - const char *format, argspec_t argspecs, size_t argspecs_len, - valueitem_t valuetable, int myerrno, size_t *nbytes) -{ - int rc = 0; - const char *s; - argspec_t arg = argspecs; - int argidx = 0; /* Only used for assertion. */ - size_t n; - value_t value; - - s = format; - while ( *s ) - { - if (*s != '%') - { - s++; - continue; - } - if (s != format) - { - rc = outfnc (outfncarg, format, (n=s-format)); - if (rc) - return rc; - *nbytes += n; - } - if (s[1] == '%') - { - /* Note that this code ignores one trailing percent escape - - this is however okay as the args parser must have - detected this already. */ - rc = outfnc (outfncarg, s, 1); - if (rc) - return rc; - *nbytes += 1; - s += 2; - format = s; - continue; - } - - /* Save the next start. */ - s += arg->length; - format = s; - - assert (argidx < argspecs_len); - argidx++; - - /* Apply indirect field width and precision values. */ - if (arg->width == STAR_FIELD_VALUE) - { - assert (valuetable[arg->width_pos-1].vt == VALTYPE_INT); - arg->width = valuetable[arg->width_pos-1].value.a_int; - if (arg->width < 0) - { - arg->width = -arg->width; - arg->flags |= FLAG_LEFT_JUST; - } - } - if (arg->precision == STAR_FIELD_VALUE) - { - assert (valuetable[arg->precision_pos-1].vt == VALTYPE_INT); - arg->precision = valuetable[arg->precision_pos-1].value.a_int; - if (arg->precision < 0) - arg->precision = NO_FIELD_VALUE; - } - - if (arg->arg_pos == -1 && arg->conspec == CONSPEC_STRERROR) - value.a_string = strerror (myerrno); - else - { - assert (arg->vt == valuetable[arg->arg_pos-1].vt); - value = valuetable[arg->arg_pos-1].value; - } - - switch (arg->conspec) - { - case CONSPEC_UNKNOWN: assert (!"bug"); break; - - case CONSPEC_DECIMAL: - case CONSPEC_UNSIGNED: - case CONSPEC_OCTAL: - case CONSPEC_HEX: - case CONSPEC_HEX_UP: - rc = pr_integer (outfnc, outfncarg, arg, value, nbytes); - break; - case CONSPEC_FLOAT: - case CONSPEC_FLOAT_UP: - case CONSPEC_EXP: - case CONSPEC_EXP_UP: - case CONSPEC_F_OR_G: - case CONSPEC_F_OR_G_UP: - case CONSPEC_HEX_EXP: - case CONSPEC_HEX_EXP_UP: - rc = pr_float (outfnc, outfncarg, arg, value, nbytes); - break; - case CONSPEC_CHAR: - rc = pr_char (outfnc, outfncarg, arg, value, nbytes); - break; - case CONSPEC_STRING: - case CONSPEC_STRERROR: - rc = pr_string (outfnc, outfncarg, arg, value, nbytes); - break; - case CONSPEC_POINTER: - rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes); - break; - case CONSPEC_BYTES_SO_FAR: - rc = pr_bytes_so_far (outfnc, outfncarg, arg, value, nbytes); - break; - } - if (rc) - return rc; - arg++; - } - - /* Print out any trailing stuff. */ - n = s - format; - rc = n? outfnc (outfncarg, format, n) : 0; - if (!rc) - *nbytes += n; - - return rc; -} - - - - -/* The versatile printf formatting routine. It expects a callback - function OUTFNC and an opaque argument OUTFNCARG used for actual - output of the formatted stuff. FORMAT is the format specification - and VAARGS a variable argumemt list matching the arguments of - FORMAT. */ -int -estream_format (estream_printf_out_t outfnc, - void *outfncarg, - const char *format, va_list vaargs) -{ - /* Buffer to hold the argspecs and a pointer to it.*/ - struct argspec_s argspecs_buffer[DEFAULT_MAX_ARGSPECS]; - argspec_t argspecs = argspecs_buffer; - size_t argspecs_len; /* Number of specifications in ARGSPECS. */ - - /* Buffer to hold the description for the values. */ - struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES]; - valueitem_t valuetable = valuetable_buffer; - - int rc; /* Return code. */ - size_t argidx; /* Used to index the argspecs array. */ - size_t validx; /* Used to index the valuetable. */ - int max_pos;/* Highest argument position. */ - - size_t nbytes = 0; /* Keep track of the number of bytes passed to - the output function. */ - - int myerrno = errno; /* Save the errno for use with "%m". */ - - - /* Parse the arguments to come up with descriptive list. We can't - do this on the fly because we need to support positional - arguments. */ - rc = parse_format (format, &argspecs, DIM(argspecs_buffer), &argspecs_len); - if (rc) - goto leave; - - /* Check that all ARG_POS fields are set. */ - for (argidx=0,max_pos=0; argidx < argspecs_len; argidx++) - { - if (argspecs[argidx].arg_pos != -1 - && argspecs[argidx].arg_pos > max_pos) - max_pos = argspecs[argidx].arg_pos; - if (argspecs[argidx].width_pos > max_pos) - max_pos = argspecs[argidx].width_pos; - if (argspecs[argidx].precision_pos > max_pos) - max_pos = argspecs[argidx].precision_pos; - } - if (!max_pos) - { - /* Fill in all the positions. */ - for (argidx=0; argidx < argspecs_len; argidx++) - { - if (argspecs[argidx].width == STAR_FIELD_VALUE) - argspecs[argidx].width_pos = ++max_pos; - if (argspecs[argidx].precision == STAR_FIELD_VALUE) - argspecs[argidx].precision_pos = ++max_pos; - if (argspecs[argidx].arg_pos != -1 ) - argspecs[argidx].arg_pos = ++max_pos; - } - } - else - { - /* Check that they are all filled. More test are done later. */ - for (argidx=0; argidx < argspecs_len; argidx++) - { - if (!argspecs[argidx].arg_pos - || (argspecs[argidx].width == STAR_FIELD_VALUE - && !argspecs[argidx].width_pos) - || (argspecs[argidx].precision == STAR_FIELD_VALUE - && !argspecs[argidx].precision_pos)) - goto leave_einval; - } - } - /* Check that there is no overflow in max_pos and that it has a - reasonable length. There may never be more elements than the - number of characters in FORMAT. */ - if (max_pos < 0 || max_pos >= strlen (format)) - goto leave_einval; - -#ifdef DEBUG - dump_argspecs (argspecs, argspecs_len); -#endif - - /* Allocate a table to hold the values. If it is small enough we - use a stack allocated buffer. */ - if (max_pos > DIM(valuetable_buffer)) - { - valuetable = calloc (max_pos, sizeof *valuetable); - if (!valuetable) - goto leave_error; - } - else - { - for (validx=0; validx < DIM(valuetable_buffer); validx++) - valuetable[validx].vt = VALTYPE_UNSUPPORTED; - } - for (argidx=0; argidx < argspecs_len; argidx++) - { - if (argspecs[argidx].arg_pos != - 1) - { - validx = argspecs[argidx].arg_pos - 1; - if (valuetable[validx].vt) - goto leave_einval; /* Already defined. */ - valuetable[validx].vt = argspecs[argidx].vt; - } - if (argspecs[argidx].width == STAR_FIELD_VALUE) - { - validx = argspecs[argidx].width_pos - 1; - if (valuetable[validx].vt) - goto leave_einval; /* Already defined. */ - valuetable[validx].vt = VALTYPE_INT; - } - if (argspecs[argidx].precision == STAR_FIELD_VALUE) - { - validx = argspecs[argidx].precision_pos - 1; - if (valuetable[validx].vt) - goto leave_einval; /* Already defined. */ - valuetable[validx].vt = VALTYPE_INT; - } - } - - /* Read all the arguments. This will error out for unsupported - types and for not given positional arguments. */ - rc = read_values (valuetable, max_pos, vaargs); - if (rc) - goto leave_einval; - -/* for (validx=0; validx < max_pos; validx++) */ -/* fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */ - - /* Everything has been collected, go ahead with the formatting. */ - rc = do_format (outfnc, outfncarg, format, - argspecs, argspecs_len, valuetable, myerrno, &nbytes); - - goto leave; - - leave_einval: - _set_errno (EINVAL); - leave_error: - rc = -1; - leave: - if (valuetable != valuetable_buffer) - free (valuetable); - if (argspecs != argspecs_buffer) - free (argspecs); - return rc; -} - - - - -/* A simple output handler utilizing stdio. */ -static int -plain_stdio_out (void *outfncarg, const char *buf, size_t buflen) -{ - FILE *fp = (FILE*)outfncarg; - - if ( fwrite (buf, buflen, 1, fp) != 1 ) - return -1; - return 0; -} - - -/* A replacement for printf. */ -int -estream_printf (const char *format, ...) -{ - int rc; - va_list arg_ptr; - - va_start (arg_ptr, format); - rc = estream_format (plain_stdio_out, stderr, format, arg_ptr); - va_end (arg_ptr); - - return rc; -} - -/* A replacement for fprintf. */ -int -estream_fprintf (FILE *fp, const char *format, ...) -{ - int rc; - va_list arg_ptr; - - va_start (arg_ptr, format); - rc = estream_format (plain_stdio_out, fp, format, arg_ptr); - va_end (arg_ptr); - - return rc; -} - -/* A replacement for vfprintf. */ -int -estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr) -{ - return estream_format (plain_stdio_out, fp, format, arg_ptr); -} - - - -/* Communication object used between estream_snprintf and - fixed_buffer_out. */ -struct fixed_buffer_parm_s -{ - size_t size; /* Size of the buffer. */ - size_t count; /* Number of bytes requested for output. */ - size_t used; /* Used size of the buffer. */ - char *buffer; /* Provided buffer. */ -}; - -/* A simple malloced buffer output handler. */ -static int -fixed_buffer_out (void *outfncarg, const char *buf, size_t buflen) -{ - struct fixed_buffer_parm_s *parm = outfncarg; - - parm->count += buflen; - - if (!parm->buffer) - ; - else if (parm->used + buflen < parm->size) - { - /* Handle the common case that everything fits into the buffer - separately. */ - memcpy (parm->buffer + parm->used, buf, buflen); - parm->used += buflen; - } - else - { - /* The slow version of above. */ - for ( ;buflen && parm->used < parm->size; buflen--) - parm->buffer[parm->used++] = *buf++; - } - - return 0; -} - - -/* A replacement for vsnprintf. */ -int -estream_vsnprintf (char *buf, size_t bufsize, - const char *format, va_list arg_ptr) -{ - struct fixed_buffer_parm_s parm; - int rc; - - parm.size = bufsize; - parm.count = 0; - parm.used = 0; - parm.buffer = bufsize?buf:NULL; - rc = estream_format (fixed_buffer_out, &parm, format, arg_ptr); - if (!rc) - rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul. */ - if (rc == -1) - return -1; - if (bufsize && buf && parm.size && parm.count >= parm.size) - buf[parm.size-1] = 0; - - parm.count--; /* Do not count the trailing nul. */ - return (int)parm.count; /* Return number of bytes which would have - been written. */ -} - -/* A replacement for snprintf. */ -int -estream_snprintf (char *buf, size_t bufsize, const char *format, ...) -{ - int rc; - va_list arg_ptr; - - va_start (arg_ptr, format); - rc = estream_vsnprintf (buf, bufsize, format, arg_ptr); - va_end (arg_ptr); - - return rc; -} - - - -/* Communication object used between estream_asprintf and - dynamic_buffer_out. */ -struct dynamic_buffer_parm_s -{ - int error_flag; /* Internal helper. */ - size_t alloced; /* Allocated size of the buffer. */ - size_t used; /* Used size of the buffer. */ - char *buffer; /* Malloced buffer. */ -}; - -/* A simple malloced buffer output handler. */ -static int -dynamic_buffer_out (void *outfncarg, const char *buf, size_t buflen) -{ - struct dynamic_buffer_parm_s *parm = outfncarg; - - if (parm->error_flag) - { - /* Just in case some formatting routine did not checked for an - error. */ - _set_errno (parm->error_flag); - return -1; - } - - if (parm->used + buflen >= parm->alloced) - { - char *p; - - parm->alloced += buflen + 512; - p = my_printf_realloc (parm->buffer, parm->alloced); - if (!p) - { - parm->error_flag = errno ? errno : ENOMEM; - /* Wipe out what we already accumulated. This is useful in - case sensitive data is formated. */ - memset (parm->buffer, 0, parm->used); - return -1; - } - parm->buffer = p; - } - memcpy (parm->buffer + parm->used, buf, buflen); - parm->used += buflen; - - return 0; -} - - -/* A replacement for vasprintf. As with the BSD of vasprintf version -1 - will be returned on error and NULL stored at BUFP. On success the - number of bytes printed will be returned. */ -int -estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) -{ - struct dynamic_buffer_parm_s parm; - int rc; - - parm.error_flag = 0; - parm.alloced = 512; - parm.used = 0; - parm.buffer = my_printf_realloc (NULL, parm.alloced); - if (!parm.buffer) - { - *bufp = NULL; - return -1; - } - - rc = estream_format (dynamic_buffer_out, &parm, format, arg_ptr); - if (!rc) - rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul. */ - /* Fixme: Should we shrink the resulting buffer? */ - if (rc != -1 && parm.error_flag) - { - rc = -1; - _set_errno (parm.error_flag); - } - if (rc == -1) - { - memset (parm.buffer, 0, parm.used); - if (parm.buffer) - my_printf_realloc (parm.buffer, 0); - *bufp = NULL; - return -1; - } - assert (parm.used); /* We have at least the terminating Nul. */ - *bufp = parm.buffer; - return parm.used - 1; /* Do not include that Nul. */ -} - -/* A replacement for asprintf. As with the BSD of asprintf version -1 - will be returned on error and NULL stored at BUFP. On success the - number of bytes printed will be returned. */ -int -estream_asprintf (char **bufp, const char *format, ...) -{ - int rc; - va_list arg_ptr; - - va_start (arg_ptr, format); - rc = estream_vasprintf (bufp, format, arg_ptr); - va_end (arg_ptr); - - return rc; -} |