diff options
author | Werner Koch <wk@gnupg.org> | 2014-08-26 17:47:22 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2014-08-26 17:47:54 +0200 |
commit | 519305feb888b529c005b40445d041a088a2f8fc (patch) | |
tree | 74994a5b568e059982ca83a0daa8b7d96035355d /common | |
parent | gpg: Allow for positional parameters in the passphrase prompt. (diff) | |
download | gnupg2-519305feb888b529c005b40445d041a088a2f8fc.tar.xz gnupg2-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 'common')
-rw-r--r-- | common/Makefile.am | 1 | ||||
-rw-r--r-- | common/asshelp2.c | 2 | ||||
-rw-r--r-- | common/audit.c | 2 | ||||
-rw-r--r-- | common/audit.h | 2 | ||||
-rw-r--r-- | common/estream-printf.c | 1855 | ||||
-rw-r--r-- | common/estream-printf.h | 149 | ||||
-rw-r--r-- | common/estream.c | 4561 | ||||
-rw-r--r-- | common/estream.h | 434 | ||||
-rw-r--r-- | common/exechelp.h | 2 | ||||
-rw-r--r-- | common/http.c | 4 | ||||
-rw-r--r-- | common/http.h | 1 | ||||
-rw-r--r-- | common/init.c | 8 | ||||
-rw-r--r-- | common/iobuf.h | 1 | ||||
-rw-r--r-- | common/logging.h | 1 | ||||
-rw-r--r-- | common/membuf.c | 2 | ||||
-rw-r--r-- | common/miscellaneous.c | 45 | ||||
-rw-r--r-- | common/t-http.c | 2 | ||||
-rw-r--r-- | common/ttyio.c | 2 | ||||
-rw-r--r-- | common/util.h | 14 | ||||
-rw-r--r-- | common/xasprintf.c | 15 |
20 files changed, 69 insertions, 7034 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index b955539c8..40fdabd17 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -59,7 +59,6 @@ endif common_sources = \ common-defs.h \ util.h i18n.c i18n.h \ - estream.c estream.h estream-printf.c estream-printf.h \ status.c status.h\ shareddefs.h \ openpgpdefs.h \ diff --git a/common/asshelp2.c b/common/asshelp2.c index a87d0d148..0a70d2b05 100644 --- a/common/asshelp2.c +++ b/common/asshelp2.c @@ -47,7 +47,7 @@ vprint_assuan_status (assuan_context_t ctx, int rc; char *buf; - rc = estream_vasprintf (&buf, format, arg_ptr); + rc = gpgrt_vasprintf (&buf, format, arg_ptr); if (rc < 0) return gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); rc = assuan_write_status (ctx, keyword, buf); diff --git a/common/audit.c b/common/audit.c index 103120a24..875e59583 100644 --- a/common/audit.c +++ b/common/audit.c @@ -381,7 +381,7 @@ writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr) { char *buf; - estream_vasprintf (&buf, format, arg_ptr); + gpgrt_vasprintf (&buf, format, arg_ptr); if (buf) { writeout (ctx, buf); diff --git a/common/audit.h b/common/audit.h index 77d8f0632..345477db7 100644 --- a/common/audit.h +++ b/common/audit.h @@ -22,8 +22,6 @@ #include <ksba.h> -#include "../common/estream.h" - struct audit_ctx_s; typedef struct audit_ctx_s *audit_ctx_t; 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; -} diff --git a/common/estream-printf.h b/common/estream-printf.h deleted file mode 100644 index ca8ad8a28..000000000 --- a/common/estream-printf.h +++ /dev/null @@ -1,149 +0,0 @@ -/* estream-printf.h - Versatile mostly C-99 compliant printf formatting. - * Copyright (C) 2007, 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. - */ - -#ifndef ESTREAM_PRINTF_H -#define ESTREAM_PRINTF_H - -#include <stdarg.h> -#include <stdio.h> - -/* To use this file with libraries the following macro is useful: - - #define _ESTREAM_EXT_SYM_PREFIX _foo_ - - This prefixes all external symbols with "_foo_". - - For the implementation of the code (estream-printf.c) the following - macros may be used to tune the implementation for certain systems: - - #define _ESTREAM_PRINTF_REALLOC foo_realloc - - Make estream_asprintf and estream_vasprintf use foo_realloc - instead of the standard realloc to allocate memory returned to - the caller. Note that foo_realloc needs to be C-90 compliant: - foo_realloc (NULL,n) is the same as a call to malloc(n) and - foo_realloc (a, 0) is the same as a call to free (a). - - #define _ESTREAM_PRINTF_EXTRA_INCLUDE "foo.h" - - This includes the file "foo.h" which may provide prototypes for - the custom memory allocation functions. - */ - - -#ifdef _ESTREAM_EXT_SYM_PREFIX -#ifndef _ESTREAM_PREFIX -#define _ESTREAM_PREFIX1(x,y) x ## y -#define _ESTREAM_PREFIX2(x,y) _ESTREAM_PREFIX1(x,y) -#define _ESTREAM_PREFIX(x) _ESTREAM_PREFIX2(_ESTREAM_EXT_SYM_PREFIX,x) -#endif /*_ESTREAM_PREFIX*/ -#define estream_printf_out_t _ESTREAM_PREFIX(estream_printf_out_t) -#define estream_format _ESTREAM_PREFIX(estream_format) -#define estream_printf _ESTREAM_PREFIX(estream_printf) -#define estream_fprintf _ESTREAM_PREFIX(estream_fprintf) -#define estream_vfprintf _ESTREAM_PREFIX(estream_vfprintf) -#define estream_snprintf _ESTREAM_PREFIX(estream_snprintf) -#define estream_vsnprintf _ESTREAM_PREFIX(estream_vsnprintf) -#define estream_asprintf _ESTREAM_PREFIX(estream_asprintf) -#define estream_vasprintf _ESTREAM_PREFIX(estream_vasprintf) -#endif /*_ESTREAM_EXT_SYM_PREFIX*/ - -#ifndef _ESTREAM_GCC_A_PRINTF -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) \ - __attribute__ ((format (__gnu_printf__,f,a))) -# elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) \ - __attribute__ ((format (printf,f,a))) -# else -# define _ESTREAM_GCC_A_PRINTF( f, a ) -# endif -#endif /*_ESTREAM_GCC_A_PRINTF*/ - - -#ifdef __cplusplus -extern "C" -{ -#if 0 -} -#endif -#endif - - -typedef int (*estream_printf_out_t) - (void *outfncarg, const char *buf, size_t buflen); - -int estream_format (estream_printf_out_t outfnc, void *outfncarg, - const char *format, va_list vaargs) - _ESTREAM_GCC_A_PRINTF(3,0); -int estream_printf (const char *format, ...) - _ESTREAM_GCC_A_PRINTF(1,2); -int estream_fprintf (FILE *fp, const char *format, ... ) - _ESTREAM_GCC_A_PRINTF(2,3); -int estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr) - _ESTREAM_GCC_A_PRINTF(2,0); -int estream_snprintf (char *buf, size_t bufsize, const char *format, ...) - _ESTREAM_GCC_A_PRINTF(3,4); -int estream_vsnprintf (char *buf,size_t bufsize, - const char *format, va_list arg_ptr) - _ESTREAM_GCC_A_PRINTF(3,0); -int estream_asprintf (char **bufp, const char *format, ...) - _ESTREAM_GCC_A_PRINTF(2,3); -int estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) - _ESTREAM_GCC_A_PRINTF(2,0); - - -#ifdef __cplusplus -} -#endif -#endif /*ESTREAM_PRINTF_H*/ diff --git a/common/estream.c b/common/estream.c deleted file mode 100644 index d21115433..000000000 --- a/common/estream.c +++ /dev/null @@ -1,4561 +0,0 @@ -/* estream.c - Extended Stream I/O Library - * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011, - * 2014 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. - */ - -#ifdef USE_ESTREAM_SUPPORT_H -# include <estream-support.h> -#endif - -#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 <sys/types.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <fcntl.h> -#include <errno.h> -#include <stddef.h> -#include <assert.h> -#ifdef HAVE_W32_SYSTEM -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# endif -# include <windows.h> -#endif -#ifdef HAVE_W32CE_SYSTEM -# include <gpg-error.h> /* ERRNO replacement. */ -#endif - -#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ -# undef HAVE_NPTH -# undef USE_NPTH -#endif - -#ifdef HAVE_NPTH -# include <npth.h> -#endif - -/* This is for the special hack to use estream.c in GnuPG. */ -#ifdef GNUPG_MAJOR_VERSION -# include "../common/util.h" -#endif - -#ifndef HAVE_MKSTEMP -int mkstemp (char *template); -#endif - -#ifndef HAVE_MEMRCHR -void *memrchr (const void *block, int c, size_t size); -#endif - -#include <estream.h> -#include <estream-printf.h> - - - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifdef HAVE_W32_SYSTEM -# define S_IRGRP S_IRUSR -# define S_IROTH S_IRUSR -# define S_IWGRP S_IWUSR -# define S_IWOTH S_IWUSR -# define S_IXGRP S_IXUSR -# define S_IXOTH S_IXUSR -#endif - - -#ifdef HAVE_W32CE_SYSTEM -# define _set_errno(a) gpg_err_set_errno ((a)) -/* Setmode is missing in cegcc but available since CE 5.0. */ -int _setmode (int handle, int mode); -# define setmode(a,b) _setmode ((a),(b)) -#else -# define _set_errno(a) do { errno = (a); } while (0) -#endif - -#ifdef HAVE_W32_SYSTEM -# define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1)) /* ?? FIXME. */ -#else -# define IS_INVALID_FD(a) ((a) == -1) -#endif - - -/* Generally used types. */ - -typedef void *(*func_realloc_t) (void *mem, size_t size); -typedef void (*func_free_t) (void *mem); - - - - -/* Buffer management layer. */ - -#define BUFFER_BLOCK_SIZE BUFSIZ -#define BUFFER_UNREAD_SIZE 16 - - -/* Primitive system I/O. */ - -#ifdef USE_NPTH -# define ESTREAM_SYS_READ do_npth_read -# define ESTREAM_SYS_WRITE do_npth_write -# define ESTREAM_SYS_YIELD() npth_usleep (0) -#else -# define ESTREAM_SYS_READ read -# define ESTREAM_SYS_WRITE write -# define ESTREAM_SYS_YIELD() do { } while (0) -#endif - - -/* A linked list to hold notification functions. */ -struct notify_list_s -{ - struct notify_list_s *next; - void (*fnc) (estream_t, void*); /* The notification function. */ - void *fnc_value; /* The value to be passed to FNC. */ -}; -typedef struct notify_list_s *notify_list_t; - - -/* A private cookie function to implement an internal IOCTL - service. */ -typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd, - void *ptr, size_t *len); -/* IOCTL commands for the private cookie function. */ -#define COOKIE_IOCTL_SNATCH_BUFFER 1 - - -/* The internal stream object. */ -struct estream_internal -{ - unsigned char buffer[BUFFER_BLOCK_SIZE]; - unsigned char unread_buffer[BUFFER_UNREAD_SIZE]; - -#ifdef USE_NPTH - npth_mutex_t lock; /* Lock. */ -#endif - - void *cookie; /* Cookie. */ - void *opaque; /* Opaque data. */ - unsigned int modeflags; /* Flags for the backend. */ - char *printable_fname; /* Malloced filename for es_fname_get. */ - off_t offset; - es_cookie_read_function_t func_read; - es_cookie_write_function_t func_write; - es_cookie_seek_function_t func_seek; - cookie_ioctl_function_t func_ioctl; - es_cookie_close_function_t func_close; - int strategy; - es_syshd_t syshd; /* A copy of the sytem handle. */ - struct - { - unsigned int err: 1; - unsigned int eof: 1; - } indicators; - unsigned int deallocate_buffer: 1; - unsigned int is_stdstream:1; /* This is a standard stream. */ - unsigned int stdstream_fd:2; /* 0, 1 or 2 for a standard stream. */ - unsigned int printable_fname_inuse: 1; /* es_fname_get has been used. */ - unsigned int samethread: 1; /* The "samethread" mode keyword. */ - size_t print_ntotal; /* Bytes written from in print_writer. */ - notify_list_t onclose; /* On close notify function list. */ -}; -typedef struct estream_internal *estream_internal_t; - -/* A linked list to hold active stream objects. */ -struct estream_list_s -{ - struct estream_list_s *next; - estream_t stream; /* Entry is not used if NULL. */ -}; -typedef struct estream_list_s *estream_list_t; -static estream_list_t estream_list; - -/* File descriptors registered to be used as the standard file handles. */ -static int custom_std_fds[3]; -static unsigned char custom_std_fds_valid[3]; - -/* A lock object for the estream list and the custom_std_fds array. */ -#ifdef USE_NPTH -static npth_mutex_t estream_list_lock; -#endif - - -/* Error code replacements. */ -#ifndef EOPNOTSUPP -# define EOPNOTSUPP ENOSYS -#endif - - -/* Local prototypes. */ -static void fname_set_internal (estream_t stream, const char *fname, int quote); - - - - -/* Macros. */ - -/* Calculate array dimension. */ -#ifndef DIM -#define DIM(array) (sizeof (array) / sizeof (*array)) -#endif - -#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) - - -/* Evaluate EXPRESSION, setting VARIABLE to the return code, if - VARIABLE is zero. */ -#define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \ - do \ - { \ - tmp_variable = expression; \ - if ((! variable) && tmp_variable) \ - variable = tmp_variable; \ - } \ - while (0) - - - -/* Malloc wrappers to overcome problems on some older OSes. */ -static void * -mem_alloc (size_t n) -{ - if (!n) - n++; - return malloc (n); -} - -static void * -mem_realloc (void *p, size_t n) -{ - if (!p) - return mem_alloc (n); - return realloc (p, n); -} - -static void -mem_free (void *p) -{ - if (p) - free (p); -} - -#ifdef HAVE_W32_SYSTEM -static int -map_w32_to_errno (DWORD w32_err) -{ - switch (w32_err) - { - case 0: - return 0; - - case ERROR_FILE_NOT_FOUND: - return ENOENT; - - case ERROR_PATH_NOT_FOUND: - return ENOENT; - - case ERROR_ACCESS_DENIED: - return EPERM; - - case ERROR_INVALID_HANDLE: - case ERROR_INVALID_BLOCK: - return EINVAL; - - case ERROR_NOT_ENOUGH_MEMORY: - return ENOMEM; - - case ERROR_NO_DATA: - return EPIPE; - - default: - return EIO; - } -} -#endif /*HAVE_W32_SYSTEM*/ - - - -/* - * Lock wrappers - */ -#if 0 -# define dbg_lock_0(f) fprintf (stderr, "estream: " f); -# define dbg_lock_1(f, a) fprintf (stderr, "estream: " f, (a)); -# define dbg_lock_2(f, a, b) fprintf (stderr, "estream: " f, (a), (b)); -#else -# define dbg_lock_0(f) -# define dbg_lock_1(f, a) -# define dbg_lock_2(f, a, b) -#endif - -static int -init_stream_lock (estream_t ES__RESTRICT stream) -{ -#ifdef USE_NPTH - int rc; - - if (!stream->intern->samethread) - { - dbg_lock_1 ("enter init_stream_lock for %p\n", stream); - rc = npth_mutex_init (&stream->intern->lock, NULL); - dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc); - } - else - rc = 0; - return rc; -#else - (void)stream; - return 0; -#endif -} - - -static void -lock_stream (estream_t ES__RESTRICT stream) -{ -#ifdef USE_NPTH - if (!stream->intern->samethread) - { - dbg_lock_1 ("enter lock_stream for %p\n", stream); - npth_mutex_lock (&stream->intern->lock); - dbg_lock_1 ("leave lock_stream for %p\n", stream); - } -#else - (void)stream; -#endif -} - - -static int -trylock_stream (estream_t ES__RESTRICT stream) -{ -#ifdef USE_NPTH - int rc; - - if (!stream->intern->samethread) - { - dbg_lock_1 ("enter trylock_stream for %p\n", stream); - rc = npth_mutex_trylock (&stream->intern->lock)? 0 : -1; - dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc); - } - else - rc = 0; - return rc; -#else - (void)stream; - return 0; -#endif -} - - -static void -unlock_stream (estream_t ES__RESTRICT stream) -{ -#ifdef USE_NPTH - if (!stream->intern->samethread) - { - dbg_lock_1 ("enter unlock_stream for %p\n", stream); - npth_mutex_unlock (&stream->intern->lock); - dbg_lock_1 ("leave unlock_stream for %p\n", stream); - } -#else - (void)stream; -#endif -} - - -static int -init_list_lock (void) -{ -#ifdef USE_NPTH - int rc; - - dbg_lock_0 ("enter init_list_lock\n"); - rc = npth_mutex_init (&estream_list_lock, NULL); - dbg_lock_1 ("leave init_list_lock: rc=%d\n", rc); - return rc; -#else - return 0; -#endif -} - - -static void -lock_list (void) -{ -#ifdef USE_NPTH - dbg_lock_0 ("enter lock_list\n"); - npth_mutex_lock (&estream_list_lock); - dbg_lock_0 ("leave lock_list\n"); -#endif -} - - -static void -unlock_list (void) -{ -#ifdef USE_NPTH - dbg_lock_0 ("enter unlock_list\n"); - npth_mutex_unlock (&estream_list_lock); - dbg_lock_0 ("leave unlock_list\n"); -#endif -} - - -#undef dbg_lock_0 -#undef dbg_lock_1 -#undef dbg_lock_2 - - - -/* - * List manipulation. - */ - -/* Add STREAM to the list of registered stream objects. If - WITH_LOCKED_LIST is true it is assumed that the list of streams is - already locked. The implementation is straightforward: We first - look for an unused entry in the list and use that; if none is - available we put a new item at the head. We drawback of the - strategy never to shorten the list is that a one time allocation of - many streams will lead to scanning unused entries later. If that - turns out to be a problem, we may either free some items from the - list or append new entries at the end; or use a table. Returns 0 - on success; on error or non-zero is returned and ERRNO set. */ -static int -do_list_add (estream_t stream, int with_locked_list) -{ - estream_list_t item; - - if (!with_locked_list) - lock_list (); - - for (item = estream_list; item && item->stream; item = item->next) - ; - if (!item) - { - item = mem_alloc (sizeof *item); - if (item) - { - item->next = estream_list; - estream_list = item; - } - } - if (item) - item->stream = stream; - - if (!with_locked_list) - unlock_list (); - - return item? 0 : -1; -} - -/* Remove STREAM from the list of registered stream objects. */ -static void -do_list_remove (estream_t stream, int with_locked_list) -{ - estream_list_t item; - - if (!with_locked_list) - lock_list (); - - for (item = estream_list; item; item = item->next) - if (item->stream == stream) - { - item->stream = NULL; - break; - } - - if (!with_locked_list) - unlock_list (); -} - - - -/* - * I/O Helper - * - * Unfortunately our Pth emulation for Windows expects system handles - * for npth_read and npth_write. We use a simple approach to fix this: - * If the function returns an error we fall back to a vanilla read or - * write, assuming that we do I/O on a plain file where the operation - * can't block. FIXME: Is this still needed for npth? - */ -#ifdef USE_NPTH -static int -do_npth_read (int fd, void *buffer, size_t size) -{ -# ifdef HAVE_W32_SYSTEM - int rc = npth_read (fd, buffer, size); - if (rc == -1 && errno == EINVAL) - rc = read (fd, buffer, size); - return rc; -# else /*!HAVE_W32_SYSTEM*/ - return npth_read (fd, buffer, size); -# endif /* !HAVE_W32_SYSTEM*/ -} - -static int -do_npth_write (int fd, const void *buffer, size_t size) -{ -# ifdef HAVE_W32_SYSTEM - int rc = npth_write (fd, buffer, size); - if (rc == -1 && errno == EINVAL) - rc = write (fd, buffer, size); - return rc; -# else /*!HAVE_W32_SYSTEM*/ - return npth_write (fd, buffer, size); -# endif /* !HAVE_W32_SYSTEM*/ -} -#endif /*USE_NPTH*/ - - - -static void -do_deinit (void) -{ - /* Flush all streams. */ - es_fflush (NULL); - - /* We should release the estream_list. However there is one - problem: That list is also used to search for the standard - estream file descriptors. If we would remove the entire list, - any use of es_foo in another atexit function may re-create the - list and the streams with possible undesirable effects. Given - that we don't close the stream either, it should not matter that - we keep the list and let the OS clean it up at process end. */ -} - - -/* - * Initialization. - */ - -static int -do_init (void) -{ - static int initialized; - - if (!initialized) - { - if (!init_list_lock ()) - initialized = 1; - atexit (do_deinit); - } - return 0; -} - - - -/* - * I/O methods. - */ - -/* Implementation of Memory I/O. */ - -/* Cookie for memory objects. */ -typedef struct estream_cookie_mem -{ - unsigned int modeflags; /* Open flags. */ - unsigned char *memory; /* Allocated data buffer. */ - size_t memory_size; /* Allocated size of MEMORY. */ - size_t memory_limit; /* Caller supplied maximum allowed - allocation size or 0 for no limit. */ - size_t offset; /* Current offset in MEMORY. */ - size_t data_len; /* Used length of data in MEMORY. */ - size_t block_size; /* Block size. */ - struct { - unsigned int grow: 1; /* MEMORY is allowed to grow. */ - } flags; - func_realloc_t func_realloc; - func_free_t func_free; -} *estream_cookie_mem_t; - - -/* Create function for memory objects. DATA is either NULL or a user - supplied buffer with the initial conetnt of the memory buffer. If - DATA is NULL, DATA_N and DATA_LEN need to be 0 as well. If DATA is - not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the - used length in DATA. If this fucntion succeeds DATA is now owned - by this function. If GROW is false FUNC_REALLOC is not - required. */ -static int -func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie, - unsigned char *ES__RESTRICT data, size_t data_n, - size_t data_len, - size_t block_size, unsigned int grow, - func_realloc_t func_realloc, func_free_t func_free, - unsigned int modeflags, - size_t memory_limit) -{ - estream_cookie_mem_t mem_cookie; - int err; - - if (!data && (data_n || data_len)) - { - _set_errno (EINVAL); - return -1; - } - if (grow && func_free && !func_realloc) - { - _set_errno (EINVAL); - return -1; - } - - mem_cookie = mem_alloc (sizeof (*mem_cookie)); - if (!mem_cookie) - err = -1; - else - { - mem_cookie->modeflags = modeflags; - mem_cookie->memory = data; - mem_cookie->memory_size = data_n; - mem_cookie->memory_limit = memory_limit; - mem_cookie->offset = 0; - mem_cookie->data_len = data_len; - mem_cookie->block_size = block_size; - mem_cookie->flags.grow = !!grow; - mem_cookie->func_realloc - = grow? (func_realloc ? func_realloc : mem_realloc) : NULL; - mem_cookie->func_free = func_free ? func_free : mem_free; - *cookie = mem_cookie; - err = 0; - } - - return err; -} - - -/* Read function for memory objects. */ -static ssize_t -es_func_mem_read (void *cookie, void *buffer, size_t size) -{ - estream_cookie_mem_t mem_cookie = cookie; - ssize_t ret; - - if (size > mem_cookie->data_len - mem_cookie->offset) - size = mem_cookie->data_len - mem_cookie->offset; - - if (size) - { - memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size); - mem_cookie->offset += size; - } - - ret = size; - return ret; -} - - -/* Write function for memory objects. */ -static ssize_t -es_func_mem_write (void *cookie, const void *buffer, size_t size) -{ - estream_cookie_mem_t mem_cookie = cookie; - ssize_t ret; - size_t nleft; - - if (!size) - return 0; /* A flush is a NOP for memory objects. */ - - if (mem_cookie->modeflags & O_APPEND) - { - /* Append to data. */ - mem_cookie->offset = mem_cookie->data_len; - } - - assert (mem_cookie->memory_size >= mem_cookie->offset); - nleft = mem_cookie->memory_size - mem_cookie->offset; - - /* If we are not allowed to grow the buffer, limit the size to the - left space. */ - if (!mem_cookie->flags.grow && size > nleft) - size = nleft; - - /* Enlarge the memory buffer if needed. */ - if (size > nleft) - { - unsigned char *newbuf; - size_t newsize; - - if (!mem_cookie->memory_size) - newsize = size; /* Not yet allocated. */ - else - newsize = mem_cookie->memory_size + (size - nleft); - if (newsize < mem_cookie->offset) - { - _set_errno (EINVAL); - return -1; - } - - /* Round up to the next block length. BLOCK_SIZE should always - be set; we check anyway. */ - if (mem_cookie->block_size) - { - newsize += mem_cookie->block_size - 1; - if (newsize < mem_cookie->offset) - { - _set_errno (EINVAL); - return -1; - } - newsize /= mem_cookie->block_size; - newsize *= mem_cookie->block_size; - } - - /* Check for a total limit. */ - if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit) - { - _set_errno (ENOSPC); - return -1; - } - - assert (mem_cookie->func_realloc); - newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize); - if (!newbuf) - return -1; - - mem_cookie->memory = newbuf; - mem_cookie->memory_size = newsize; - - assert (mem_cookie->memory_size >= mem_cookie->offset); - nleft = mem_cookie->memory_size - mem_cookie->offset; - - assert (size <= nleft); - } - - memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size); - if (mem_cookie->offset + size > mem_cookie->data_len) - mem_cookie->data_len = mem_cookie->offset + size; - mem_cookie->offset += size; - - ret = size; - return ret; -} - - -/* Seek function for memory objects. */ -static int -es_func_mem_seek (void *cookie, off_t *offset, int whence) -{ - estream_cookie_mem_t mem_cookie = cookie; - off_t pos_new; - - switch (whence) - { - case SEEK_SET: - pos_new = *offset; - break; - - case SEEK_CUR: - pos_new = mem_cookie->offset += *offset; - break; - - case SEEK_END: - pos_new = mem_cookie->data_len += *offset; - break; - - default: - _set_errno (EINVAL); - return -1; - } - - if (pos_new > mem_cookie->memory_size) - { - size_t newsize; - void *newbuf; - - if (!mem_cookie->flags.grow) - { - _set_errno (ENOSPC); - return -1; - } - - newsize = pos_new + mem_cookie->block_size - 1; - if (newsize < pos_new) - { - _set_errno (EINVAL); - return -1; - } - newsize /= mem_cookie->block_size; - newsize *= mem_cookie->block_size; - - if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit) - { - _set_errno (ENOSPC); - return -1; - } - - assert (mem_cookie->func_realloc); - newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize); - if (!newbuf) - return -1; - - mem_cookie->memory = newbuf; - mem_cookie->memory_size = newsize; - } - - if (pos_new > mem_cookie->data_len) - { - /* Fill spare space with zeroes. */ - memset (mem_cookie->memory + mem_cookie->data_len, - 0, pos_new - mem_cookie->data_len); - mem_cookie->data_len = pos_new; - } - - mem_cookie->offset = pos_new; - *offset = pos_new; - - return 0; -} - -/* An IOCTL function for memory objects. */ -static int -es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len) -{ - estream_cookie_mem_t mem_cookie = cookie; - int ret; - - if (cmd == COOKIE_IOCTL_SNATCH_BUFFER) - { - /* Return the internal buffer of the stream to the caller and - invalidate it for the stream. */ - *(void**)ptr = mem_cookie->memory; - *len = mem_cookie->offset; - mem_cookie->memory = NULL; - mem_cookie->memory_size = 0; - mem_cookie->offset = 0; - ret = 0; - } - else - { - _set_errno (EINVAL); - ret = -1; - } - - return ret; -} - - -/* Destroy function for memory objects. */ -static int -es_func_mem_destroy (void *cookie) -{ - estream_cookie_mem_t mem_cookie = cookie; - - if (cookie) - { - mem_cookie->func_free (mem_cookie->memory); - mem_free (mem_cookie); - } - return 0; -} - - -static es_cookie_io_functions_t estream_functions_mem = - { - es_func_mem_read, - es_func_mem_write, - es_func_mem_seek, - es_func_mem_destroy - }; - - - -/* Implementation of file descriptor based I/O. */ - -/* Cookie for fd objects. */ -typedef struct estream_cookie_fd -{ - int fd; /* The file descriptor we are using for actual output. */ - int no_close; /* If set we won't close the file descriptor. */ -} *estream_cookie_fd_t; - -/* Create function for objects indentified by a libc file descriptor. */ -static int -func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close) -{ - estream_cookie_fd_t fd_cookie; - int err; - - fd_cookie = mem_alloc (sizeof (*fd_cookie)); - if (! fd_cookie) - err = -1; - else - { -#ifdef HAVE_DOSISH_SYSTEM - /* Make sure it is in binary mode if requested. */ - if ( (modeflags & O_BINARY) ) - setmode (fd, O_BINARY); -#else - (void)modeflags; -#endif - fd_cookie->fd = fd; - fd_cookie->no_close = no_close; - *cookie = fd_cookie; - err = 0; - } - - return err; -} - -/* Read function for fd objects. */ -static ssize_t -es_func_fd_read (void *cookie, void *buffer, size_t size) - -{ - estream_cookie_fd_t file_cookie = cookie; - ssize_t bytes_read; - - if (IS_INVALID_FD (file_cookie->fd)) - { - ESTREAM_SYS_YIELD (); - bytes_read = 0; - } - else - { - do - bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size); - while (bytes_read == -1 && errno == EINTR); - } - - return bytes_read; -} - -/* Write function for fd objects. */ -static ssize_t -es_func_fd_write (void *cookie, const void *buffer, size_t size) -{ - estream_cookie_fd_t file_cookie = cookie; - ssize_t bytes_written; - - if (IS_INVALID_FD (file_cookie->fd)) - { - ESTREAM_SYS_YIELD (); - bytes_written = size; /* Yeah: Success writing to the bit bucket. */ - } - else - { - do - bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size); - while (bytes_written == -1 && errno == EINTR); - } - - return bytes_written; -} - -/* Seek function for fd objects. */ -static int -es_func_fd_seek (void *cookie, off_t *offset, int whence) -{ - estream_cookie_fd_t file_cookie = cookie; - off_t offset_new; - int err; - - if (IS_INVALID_FD (file_cookie->fd)) - { - _set_errno (ESPIPE); - err = -1; - } - else - { - offset_new = lseek (file_cookie->fd, *offset, whence); - if (offset_new == -1) - err = -1; - else - { - *offset = offset_new; - err = 0; - } - } - - return err; -} - -/* Destroy function for fd objects. */ -static int -es_func_fd_destroy (void *cookie) -{ - estream_cookie_fd_t fd_cookie = cookie; - int err; - - if (fd_cookie) - { - if (IS_INVALID_FD (fd_cookie->fd)) - err = 0; - else - err = fd_cookie->no_close? 0 : close (fd_cookie->fd); - mem_free (fd_cookie); - } - else - err = 0; - - return err; -} - - -static es_cookie_io_functions_t estream_functions_fd = - { - es_func_fd_read, - es_func_fd_write, - es_func_fd_seek, - es_func_fd_destroy - }; - - - - -#ifdef HAVE_W32_SYSTEM -/* Implementation of W32 handle based I/O. */ - -/* Cookie for fd objects. */ -typedef struct estream_cookie_w32 -{ - HANDLE hd; /* The handle we are using for actual output. */ - int no_close; /* If set we won't close the handle. */ -} *estream_cookie_w32_t; - - -/* Create function for w32 handle objects. */ -static int -es_func_w32_create (void **cookie, HANDLE hd, - unsigned int modeflags, int no_close) -{ - estream_cookie_w32_t w32_cookie; - int err; - - w32_cookie = mem_alloc (sizeof (*w32_cookie)); - if (!w32_cookie) - err = -1; - else - { - /* CR/LF translations are not supported when using the bare W32 - API. If that is really required we need to implemented that - in the upper layer. */ - (void)modeflags; - - w32_cookie->hd = hd; - w32_cookie->no_close = no_close; - *cookie = w32_cookie; - err = 0; - } - - return err; -} - -/* Read function for W32 handle objects. */ -static ssize_t -es_func_w32_read (void *cookie, void *buffer, size_t size) -{ - estream_cookie_w32_t w32_cookie = cookie; - ssize_t bytes_read; - - if (w32_cookie->hd == INVALID_HANDLE_VALUE) - { - ESTREAM_SYS_YIELD (); - bytes_read = 0; - } - else - { - do - { -#ifdef USE_NPTH - /* Note: Our pth_read actually uses HANDLE! - FIXME: Check whether this is the case for npth. */ - bytes_read = npth_read ((int)w32_cookie->hd, buffer, size); -#else - DWORD nread, ec; - - if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL)) - { - ec = GetLastError (); - if (ec == ERROR_BROKEN_PIPE) - bytes_read = 0; /* Like our pth_read we handle this as EOF. */ - else - { - _set_errno (map_w32_to_errno (ec)); - log_debug ("estream: ReadFile returned %d\n", - (int)GetLastError ()); - bytes_read = -1; - } - } - else - bytes_read = (int)nread; -#endif - } - while (bytes_read == -1 && errno == EINTR); - } - - return bytes_read; -} - -/* Write function for W32 handle objects. */ -static ssize_t -es_func_w32_write (void *cookie, const void *buffer, size_t size) -{ - estream_cookie_w32_t w32_cookie = cookie; - ssize_t bytes_written; - - if (w32_cookie->hd == INVALID_HANDLE_VALUE) - { - ESTREAM_SYS_YIELD (); - bytes_written = size; /* Yeah: Success writing to the bit bucket. */ - } - else - { - do - { -#ifdef USE_NPTH - /* Note: Our pth_write actually uses HANDLE! */ - bytes_written = npth_write ((int)w32_cookie->hd, buffer, size); -#else - DWORD nwritten; - - if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL)) - { - _set_errno (map_w32_to_errno (GetLastError ())); - bytes_written = -1; - } - else - bytes_written = (int)nwritten; -#endif - } - while (bytes_written == -1 && errno == EINTR); - } - - return bytes_written; -} - -/* Seek function for W32 handle objects. */ -static int -es_func_w32_seek (void *cookie, off_t *offset, int whence) -{ - estream_cookie_w32_t w32_cookie = cookie; - DWORD method; - LARGE_INTEGER distance, newoff; - - if (w32_cookie->hd == INVALID_HANDLE_VALUE) - { - _set_errno (ESPIPE); - return -1; - } - - if (whence == SEEK_SET) - { - method = FILE_BEGIN; - distance.QuadPart = (unsigned long long)(*offset); - } - else if (whence == SEEK_CUR) - { - method = FILE_CURRENT; - distance.QuadPart = (long long)(*offset); - } - else if (whence == SEEK_END) - { - method = FILE_END; - distance.QuadPart = (long long)(*offset); - } - else - { - _set_errno (EINVAL); - return -1; - } -#ifdef HAVE_W32CE_SYSTEM -# warning need to use SetFilePointer -#else - if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method)) - { - _set_errno (map_w32_to_errno (GetLastError ())); - return -1; - } -#endif - *offset = (unsigned long long)newoff.QuadPart; - return 0; -} - -/* Destroy function for W32 handle objects. */ -static int -es_func_w32_destroy (void *cookie) -{ - estream_cookie_w32_t w32_cookie = cookie; - int err; - - if (w32_cookie) - { - if (w32_cookie->hd == INVALID_HANDLE_VALUE) - err = 0; - else if (w32_cookie->no_close) - err = 0; - else - { - if (!CloseHandle (w32_cookie->hd)) - { - _set_errno (map_w32_to_errno (GetLastError ())); - err = -1; - } - else - err = 0; - } - mem_free (w32_cookie); - } - else - err = 0; - - return err; -} - - -static es_cookie_io_functions_t estream_functions_w32 = - { - es_func_w32_read, - es_func_w32_write, - es_func_w32_seek, - es_func_w32_destroy - }; -#endif /*HAVE_W32_SYSTEM*/ - - - - -/* Implementation of FILE* I/O. */ - -/* Cookie for fp objects. */ -typedef struct estream_cookie_fp -{ - FILE *fp; /* The file pointer we are using for actual output. */ - int no_close; /* If set we won't close the file pointer. */ -} *estream_cookie_fp_t; - - -/* Create function for FILE objects. */ -static int -func_fp_create (void **cookie, FILE *fp, - unsigned int modeflags, int no_close) -{ - estream_cookie_fp_t fp_cookie; - int err; - - fp_cookie = mem_alloc (sizeof *fp_cookie); - if (!fp_cookie) - err = -1; - else - { -#ifdef HAVE_DOSISH_SYSTEM - /* Make sure it is in binary mode if requested. */ - if ( (modeflags & O_BINARY) ) - setmode (fileno (fp), O_BINARY); -#else - (void)modeflags; -#endif - fp_cookie->fp = fp; - fp_cookie->no_close = no_close; - *cookie = fp_cookie; - err = 0; - } - - return err; -} - -/* Read function for FILE* objects. */ -static ssize_t -es_func_fp_read (void *cookie, void *buffer, size_t size) - -{ - estream_cookie_fp_t file_cookie = cookie; - ssize_t bytes_read; - - if (file_cookie->fp) - bytes_read = fread (buffer, 1, size, file_cookie->fp); - else - bytes_read = 0; - if (!bytes_read && ferror (file_cookie->fp)) - return -1; - return bytes_read; -} - -/* Write function for FILE* objects. */ -static ssize_t -es_func_fp_write (void *cookie, const void *buffer, size_t size) -{ - estream_cookie_fp_t file_cookie = cookie; - size_t bytes_written; - - if (file_cookie->fp) - { -#ifdef HAVE_W32_SYSTEM - /* Using an fwrite to stdout connected to the console fails with - the error "Not enough space" for an fwrite size of >= 52KB - (tested on Windows XP SP2). To solve this we always chunk - the writes up into smaller blocks. */ - bytes_written = 0; - while (bytes_written < size) - { - size_t cnt = size - bytes_written; - - if (cnt > 32*1024) - cnt = 32*1024; - if (fwrite ((const char*)buffer + bytes_written, - cnt, 1, file_cookie->fp) != 1) - break; /* Write error. */ - bytes_written += cnt; - } -#else - bytes_written = fwrite (buffer, 1, size, file_cookie->fp); -#endif - fflush (file_cookie->fp); - } - else - bytes_written = size; /* Successfully written to the bit bucket. */ - if (bytes_written != size) - return -1; - return bytes_written; -} - -/* Seek function for FILE* objects. */ -static int -es_func_fp_seek (void *cookie, off_t *offset, int whence) -{ - estream_cookie_fp_t file_cookie = cookie; - long int offset_new; - - if (!file_cookie->fp) - { - _set_errno (ESPIPE); - return -1; - } - - if ( fseek (file_cookie->fp, (long int)*offset, whence) ) - { - /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */ - /* errno,strerror (errno)); */ - return -1; - } - - offset_new = ftell (file_cookie->fp); - if (offset_new == -1) - { - /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n", */ - /* errno,strerror (errno)); */ - return -1; - } - *offset = offset_new; - return 0; -} - -/* Destroy function for FILE* objects. */ -static int -es_func_fp_destroy (void *cookie) -{ - estream_cookie_fp_t fp_cookie = cookie; - int err; - - if (fp_cookie) - { - if (fp_cookie->fp) - { - fflush (fp_cookie->fp); - err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp); - } - else - err = 0; - mem_free (fp_cookie); - } - else - err = 0; - - return err; -} - - -static es_cookie_io_functions_t estream_functions_fp = - { - es_func_fp_read, - es_func_fp_write, - es_func_fp_seek, - es_func_fp_destroy - }; - - - - -/* Implementation of file I/O. */ - -/* Create function for objects identified by a file name. */ -static int -func_file_create (void **cookie, int *filedes, - const char *path, unsigned int modeflags, unsigned int cmode) -{ - estream_cookie_fd_t file_cookie; - int err; - int fd; - - err = 0; - fd = -1; - - file_cookie = mem_alloc (sizeof (*file_cookie)); - if (! file_cookie) - { - err = -1; - goto out; - } - - fd = open (path, modeflags, cmode); - if (fd == -1) - { - err = -1; - goto out; - } -#ifdef HAVE_DOSISH_SYSTEM - /* Make sure it is in binary mode if requested. */ - if ( (modeflags & O_BINARY) ) - setmode (fd, O_BINARY); -#endif - - file_cookie->fd = fd; - file_cookie->no_close = 0; - *cookie = file_cookie; - *filedes = fd; - - out: - - if (err) - mem_free (file_cookie); - - return err; -} - - - -/* Parse the mode flags of fopen et al. In addition to the POSIX - defined mode flags keyword parameters are supported. These are - key/value pairs delimited by comma and optional white spaces. - Keywords and values may not contain a comma or white space; unknown - keywords are skipped. Supported keywords are: - - mode=<string> - - Creates a file and gives the new file read and write permissions - for the user and read permission for the group. The format of - the string is the same as shown by the -l option of the ls(1) - command. However the first letter must be a dash and it is - allowed to leave out trailing dashes. If this keyword parameter - is not given the default mode for creating files is "-rw-rw-r--" - (664). Note that the system still applies the current umask to - the mode when crating a file. Example: - - "wb,mode=-rw-r--" - - samethread - - Assumes that the object is only used by the creating thread and - disables any internal locking. This keyword is also found on - IBM systems. - - - Note: R_CMODE is optional because is only required by functions - which are able to creat a file. */ -static int -parse_mode (const char *modestr, - unsigned int *modeflags, int *samethread, - unsigned int *r_cmode) -{ - unsigned int omode, oflags, cmode; - int got_cmode = 0; - - *samethread = 0; - - switch (*modestr) - { - case 'r': - omode = O_RDONLY; - oflags = 0; - break; - case 'w': - omode = O_WRONLY; - oflags = O_TRUNC | O_CREAT; - break; - case 'a': - omode = O_WRONLY; - oflags = O_APPEND | O_CREAT; - break; - default: - _set_errno (EINVAL); - return -1; - } - for (modestr++; *modestr; modestr++) - { - switch (*modestr) - { - case '+': - omode = O_RDWR; - break; - case 'b': - oflags |= O_BINARY; - break; - case 'x': - oflags |= O_EXCL; - break; - case ',': - goto keyvalue; - default: /* Ignore unknown flags. */ - break; - } - } - - keyvalue: - /* Parse key/value pairs (similar to fopen on mainframes). */ - for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ",")) - { - modestr++; - modestr += strspn (modestr, " \t"); - if (!strncmp (modestr, "mode=", 5)) - { - static struct { - char letter; - unsigned int value; - } table[] = { { '-', 0 }, - { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR }, - { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP }, - { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }}; - int idx; - - got_cmode = 1; - modestr += 5; - /* For now we only support a string as used by ls(1) and no - octal numbers. The first character must be a dash. */ - for (idx=0; idx < 10 && *modestr; idx++, modestr++) - { - if (*modestr == table[idx].letter) - cmode |= table[idx].value; - else if (*modestr != '-') - break; - } - if (*modestr && !strchr (" \t,", *modestr)) - { - _set_errno (EINVAL); - return -1; - } - } - else if (!strncmp (modestr, "samethread", 10)) - { - modestr += 10; - if (*modestr && !strchr (" \t,", *modestr)) - { - _set_errno (EINVAL); - return -1; - } - *samethread = 1; - } - } - if (!got_cmode) - cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); - - *modeflags = (omode | oflags); - if (r_cmode) - *r_cmode = cmode; - return 0; -} - - - -/* - * Low level stream functionality. - */ - -static int -es_fill (estream_t stream) -{ - size_t bytes_read = 0; - int err; - - if (!stream->intern->func_read) - { - _set_errno (EOPNOTSUPP); - err = -1; - } - else - { - es_cookie_read_function_t func_read = stream->intern->func_read; - ssize_t ret; - - ret = (*func_read) (stream->intern->cookie, - stream->buffer, stream->buffer_size); - if (ret == -1) - { - bytes_read = 0; - err = -1; - } - else - { - bytes_read = ret; - err = 0; - } - } - - if (err) - stream->intern->indicators.err = 1; - else if (!bytes_read) - stream->intern->indicators.eof = 1; - - stream->intern->offset += stream->data_len; - stream->data_len = bytes_read; - stream->data_offset = 0; - - return err; -} - -static int -es_flush (estream_t stream) -{ - es_cookie_write_function_t func_write = stream->intern->func_write; - int err; - - assert (stream->flags.writing); - - if (stream->data_offset) - { - size_t bytes_written; - size_t data_flushed; - ssize_t ret; - - if (! func_write) - { - err = EOPNOTSUPP; - goto out; - } - - /* Note: to prevent an endless loop caused by user-provided - write-functions that pretend to have written more bytes than - they were asked to write, we have to check for - "(stream->data_offset - data_flushed) > 0" instead of - "stream->data_offset - data_flushed". */ - - data_flushed = 0; - err = 0; - - while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err)) - { - ret = (*func_write) (stream->intern->cookie, - stream->buffer + data_flushed, - stream->data_offset - data_flushed); - if (ret == -1) - { - bytes_written = 0; - err = -1; - } - else - bytes_written = ret; - - data_flushed += bytes_written; - if (err) - break; - } - - stream->data_flushed += data_flushed; - if (stream->data_offset == data_flushed) - { - stream->intern->offset += stream->data_offset; - stream->data_offset = 0; - stream->data_flushed = 0; - - /* Propagate flush event. */ - (*func_write) (stream->intern->cookie, NULL, 0); - } - } - else - err = 0; - - out: - - if (err) - stream->intern->indicators.err = 1; - - return err; -} - -/* Discard buffered data for STREAM. */ -static void -es_empty (estream_t stream) -{ - assert (!stream->flags.writing); - stream->data_len = 0; - stream->data_offset = 0; - stream->unread_data_len = 0; -} - -/* Initialize STREAM. */ -static void -init_stream_obj (estream_t stream, - void *cookie, es_syshd_t *syshd, - es_cookie_io_functions_t functions, - unsigned int modeflags, int samethread) -{ - stream->intern->cookie = cookie; - stream->intern->opaque = NULL; - stream->intern->offset = 0; - stream->intern->func_read = functions.func_read; - stream->intern->func_write = functions.func_write; - stream->intern->func_seek = functions.func_seek; - stream->intern->func_ioctl = NULL; - stream->intern->func_close = functions.func_close; - stream->intern->strategy = _IOFBF; - stream->intern->syshd = *syshd; - stream->intern->print_ntotal = 0; - stream->intern->indicators.err = 0; - stream->intern->indicators.eof = 0; - stream->intern->is_stdstream = 0; - stream->intern->stdstream_fd = 0; - stream->intern->deallocate_buffer = 0; - stream->intern->printable_fname = NULL; - stream->intern->printable_fname_inuse = 0; - stream->intern->samethread = !!samethread; - stream->intern->onclose = NULL; - - stream->data_len = 0; - stream->data_offset = 0; - stream->data_flushed = 0; - stream->unread_data_len = 0; - /* Depending on the modeflags we set whether we start in writing or - reading mode. This is required in case we are working on a - stream which is not seeekable (like stdout). Without this - pre-initialization we would do a seek at the first write call and - as this will fail no utput will be delivered. */ - if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) ) - stream->flags.writing = 1; - else - stream->flags.writing = 0; -} - -/* Deinitialize STREAM. */ -static int -es_deinitialize (estream_t stream) -{ - es_cookie_close_function_t func_close; - int err, tmp_err; - - func_close = stream->intern->func_close; - - err = 0; - if (stream->flags.writing) - SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream)); - if (func_close) - SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie)); - - mem_free (stream->intern->printable_fname); - stream->intern->printable_fname = NULL; - stream->intern->printable_fname_inuse = 0; - while (stream->intern->onclose) - { - notify_list_t tmp = stream->intern->onclose->next; - mem_free (stream->intern->onclose); - stream->intern->onclose = tmp; - } - - return err; -} - -/* Create a new stream object, initialize it. */ -static int -es_create (estream_t *stream, void *cookie, es_syshd_t *syshd, - es_cookie_io_functions_t functions, unsigned int modeflags, - int samethread, int with_locked_list) -{ - estream_internal_t stream_internal_new; - estream_t stream_new; - int err; - - stream_new = NULL; - stream_internal_new = NULL; - - stream_new = mem_alloc (sizeof (*stream_new)); - if (! stream_new) - { - err = -1; - goto out; - } - - stream_internal_new = mem_alloc (sizeof (*stream_internal_new)); - if (! stream_internal_new) - { - err = -1; - goto out; - } - - stream_new->buffer = stream_internal_new->buffer; - stream_new->buffer_size = sizeof (stream_internal_new->buffer); - stream_new->unread_buffer = stream_internal_new->unread_buffer; - stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer); - stream_new->intern = stream_internal_new; - - init_stream_obj (stream_new, cookie, syshd, functions, modeflags, samethread); - init_stream_lock (stream_new); - - err = do_list_add (stream_new, with_locked_list); - if (err) - goto out; - - *stream = stream_new; - - out: - - if (err) - { - if (stream_new) - { - es_deinitialize (stream_new); - mem_free (stream_new); - } - } - - return err; -} - -/* Deinitialize a stream object and destroy it. */ -static int -do_close (estream_t stream, int with_locked_list) -{ - int err; - - if (stream) - { - do_list_remove (stream, with_locked_list); - while (stream->intern->onclose) - { - notify_list_t tmp = stream->intern->onclose->next; - - if (stream->intern->onclose->fnc) - stream->intern->onclose->fnc (stream, - stream->intern->onclose->fnc_value); - mem_free (stream->intern->onclose); - stream->intern->onclose = tmp; - } - err = es_deinitialize (stream); - mem_free (stream->intern); - mem_free (stream); - } - else - err = 0; - - return err; -} - - -/* This worker function is called with a locked stream. */ -static int -do_onclose (estream_t stream, int mode, - void (*fnc) (estream_t, void*), void *fnc_value) -{ - notify_list_t item; - - if (!mode) - { - for (item = stream->intern->onclose; item; item = item->next) - if (item->fnc && item->fnc == fnc && item->fnc_value == fnc_value) - item->fnc = NULL; /* Disable this notification. */ - } - else - { - item = mem_alloc (sizeof *item); - if (!item) - return -1; - item->fnc = fnc; - item->fnc_value = fnc_value; - item->next = stream->intern->onclose; - stream->intern->onclose = item; - } - return 0; -} - - -/* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in - unbuffered-mode, storing the amount of bytes read in - *BYTES_READ. */ -static int -es_read_nbf (estream_t ES__RESTRICT stream, - unsigned char *ES__RESTRICT buffer, - size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) -{ - es_cookie_read_function_t func_read = stream->intern->func_read; - size_t data_read; - ssize_t ret; - int err; - - data_read = 0; - err = 0; - - while (bytes_to_read - data_read) - { - ret = (*func_read) (stream->intern->cookie, - buffer + data_read, bytes_to_read - data_read); - if (ret == -1) - { - err = -1; - break; - } - else if (ret) - data_read += ret; - else - break; - } - - stream->intern->offset += data_read; - *bytes_read = data_read; - - return err; -} - -/* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in - fully-buffered-mode, storing the amount of bytes read in - *BYTES_READ. */ -static int -es_read_fbf (estream_t ES__RESTRICT stream, - unsigned char *ES__RESTRICT buffer, - size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) -{ - size_t data_available; - size_t data_to_read; - size_t data_read; - int err; - - data_read = 0; - err = 0; - - while ((bytes_to_read - data_read) && (! err)) - { - if (stream->data_offset == stream->data_len) - { - /* Nothing more to read in current container, try to - fill container with new data. */ - err = es_fill (stream); - if (! err) - if (! stream->data_len) - /* Filling did not result in any data read. */ - break; - } - - if (! err) - { - /* Filling resulted in some new data. */ - - data_to_read = bytes_to_read - data_read; - data_available = stream->data_len - stream->data_offset; - if (data_to_read > data_available) - data_to_read = data_available; - - memcpy (buffer + data_read, - stream->buffer + stream->data_offset, data_to_read); - stream->data_offset += data_to_read; - data_read += data_to_read; - } - } - - *bytes_read = data_read; - - return err; -} - -/* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in - line-buffered-mode, storing the amount of bytes read in - *BYTES_READ. */ -static int -es_read_lbf (estream_t ES__RESTRICT stream, - unsigned char *ES__RESTRICT buffer, - size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) -{ - int err; - - err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read); - - return err; -} - -/* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing - *the amount of bytes read in BYTES_READ. */ -static int -es_readn (estream_t ES__RESTRICT stream, - void *ES__RESTRICT buffer_arg, - size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) -{ - unsigned char *buffer = (unsigned char *)buffer_arg; - size_t data_read_unread, data_read; - int err; - - data_read_unread = 0; - data_read = 0; - err = 0; - - if (stream->flags.writing) - { - /* Switching to reading mode -> flush output. */ - err = es_flush (stream); - if (err) - goto out; - stream->flags.writing = 0; - } - - /* Read unread data first. */ - while ((bytes_to_read - data_read_unread) && stream->unread_data_len) - { - buffer[data_read_unread] - = stream->unread_buffer[stream->unread_data_len - 1]; - stream->unread_data_len--; - data_read_unread++; - } - - switch (stream->intern->strategy) - { - case _IONBF: - err = es_read_nbf (stream, - buffer + data_read_unread, - bytes_to_read - data_read_unread, &data_read); - break; - case _IOLBF: - err = es_read_lbf (stream, - buffer + data_read_unread, - bytes_to_read - data_read_unread, &data_read); - break; - case _IOFBF: - err = es_read_fbf (stream, - buffer + data_read_unread, - bytes_to_read - data_read_unread, &data_read); - break; - } - - out: - - if (bytes_read) - *bytes_read = data_read_unread + data_read; - - return err; -} - -/* Try to unread DATA_N bytes from DATA into STREAM, storing the - amount of bytes successfully unread in *BYTES_UNREAD. */ -static void -es_unreadn (estream_t ES__RESTRICT stream, - const unsigned char *ES__RESTRICT data, size_t data_n, - size_t *ES__RESTRICT bytes_unread) -{ - size_t space_left; - - space_left = stream->unread_buffer_size - stream->unread_data_len; - - if (data_n > space_left) - data_n = space_left; - - if (! data_n) - goto out; - - memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n); - stream->unread_data_len += data_n; - stream->intern->indicators.eof = 0; - - out: - - if (bytes_unread) - *bytes_unread = data_n; -} - -/* Seek in STREAM. */ -static int -es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence, - off_t *ES__RESTRICT offset_new) -{ - es_cookie_seek_function_t func_seek = stream->intern->func_seek; - int err, ret; - off_t off; - - if (! func_seek) - { - _set_errno (EOPNOTSUPP); - err = -1; - goto out; - } - - if (stream->flags.writing) - { - /* Flush data first in order to prevent flushing it to the wrong - offset. */ - err = es_flush (stream); - if (err) - goto out; - stream->flags.writing = 0; - } - - off = offset; - if (whence == SEEK_CUR) - { - off = off - stream->data_len + stream->data_offset; - off -= stream->unread_data_len; - } - - ret = (*func_seek) (stream->intern->cookie, &off, whence); - if (ret == -1) - { - err = -1; - goto out; - } - - err = 0; - es_empty (stream); - - if (offset_new) - *offset_new = off; - - stream->intern->indicators.eof = 0; - stream->intern->offset = off; - - out: - - if (err) - stream->intern->indicators.err = 1; - - return err; -} - -/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in - unbuffered-mode, storing the amount of bytes written in - *BYTES_WRITTEN. */ -static int -es_write_nbf (estream_t ES__RESTRICT stream, - const unsigned char *ES__RESTRICT buffer, - size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) -{ - es_cookie_write_function_t func_write = stream->intern->func_write; - size_t data_written; - ssize_t ret; - int err; - - if (bytes_to_write && (! func_write)) - { - err = EOPNOTSUPP; - goto out; - } - - data_written = 0; - err = 0; - - while (bytes_to_write - data_written) - { - ret = (*func_write) (stream->intern->cookie, - buffer + data_written, - bytes_to_write - data_written); - if (ret == -1) - { - err = -1; - break; - } - else - data_written += ret; - } - - stream->intern->offset += data_written; - *bytes_written = data_written; - - out: - - return err; -} - -/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in - fully-buffered-mode, storing the amount of bytes written in - *BYTES_WRITTEN. */ -static int -es_write_fbf (estream_t ES__RESTRICT stream, - const unsigned char *ES__RESTRICT buffer, - size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) -{ - size_t space_available; - size_t data_to_write; - size_t data_written; - int err; - - data_written = 0; - err = 0; - - while ((bytes_to_write - data_written) && (! err)) - { - if (stream->data_offset == stream->buffer_size) - /* Container full, flush buffer. */ - err = es_flush (stream); - - if (! err) - { - /* Flushing resulted in empty container. */ - - data_to_write = bytes_to_write - data_written; - space_available = stream->buffer_size - stream->data_offset; - if (data_to_write > space_available) - data_to_write = space_available; - - memcpy (stream->buffer + stream->data_offset, - buffer + data_written, data_to_write); - stream->data_offset += data_to_write; - data_written += data_to_write; - } - } - - *bytes_written = data_written; - - return err; -} - - -/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in - line-buffered-mode, storing the amount of bytes written in - *BYTES_WRITTEN. */ -static int -es_write_lbf (estream_t ES__RESTRICT stream, - const unsigned char *ES__RESTRICT buffer, - size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) -{ - size_t data_flushed = 0; - size_t data_buffered = 0; - unsigned char *nlp; - int err = 0; - - nlp = memrchr (buffer, '\n', bytes_to_write); - if (nlp) - { - /* Found a newline, directly write up to (including) this - character. */ - err = es_flush (stream); - if (!err) - err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed); - } - - if (!err) - { - /* Write remaining data fully buffered. */ - err = es_write_fbf (stream, buffer + data_flushed, - bytes_to_write - data_flushed, &data_buffered); - } - - *bytes_written = data_flushed + data_buffered; - return err; -} - - -/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the - amount of bytes written in BYTES_WRITTEN. */ -static int -es_writen (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, - size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) -{ - size_t data_written; - int err; - - data_written = 0; - err = 0; - - if (!stream->flags.writing) - { - /* Switching to writing mode -> discard input data and seek to - position at which reading has stopped. We can do this only - if a seek function has been registered. */ - if (stream->intern->func_seek) - { - err = es_seek (stream, 0, SEEK_CUR, NULL); - if (err) - { - if (errno == ESPIPE) - err = 0; - else - goto out; - } - } - } - - switch (stream->intern->strategy) - { - case _IONBF: - err = es_write_nbf (stream, buffer, bytes_to_write, &data_written); - break; - - case _IOLBF: - err = es_write_lbf (stream, buffer, bytes_to_write, &data_written); - break; - - case _IOFBF: - err = es_write_fbf (stream, buffer, bytes_to_write, &data_written); - break; - } - - out: - - if (bytes_written) - *bytes_written = data_written; - if (data_written) - if (!stream->flags.writing) - stream->flags.writing = 1; - - return err; -} - - -static int -es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data, - size_t *ES__RESTRICT data_len) -{ - int err; - - if (stream->flags.writing) - { - /* Switching to reading mode -> flush output. */ - err = es_flush (stream); - if (err) - goto out; - stream->flags.writing = 0; - } - - if (stream->data_offset == stream->data_len) - { - /* Refill container. */ - err = es_fill (stream); - if (err) - goto out; - } - - if (data) - *data = stream->buffer + stream->data_offset; - if (data_len) - *data_len = stream->data_len - stream->data_offset; - err = 0; - - out: - - return err; -} - - -/* Skip SIZE bytes of input data contained in buffer. */ -static int -es_skip (estream_t stream, size_t size) -{ - int err; - - if (stream->data_offset + size > stream->data_len) - { - _set_errno (EINVAL); - err = -1; - } - else - { - stream->data_offset += size; - err = 0; - } - - return err; -} - - -static int -doreadline (estream_t ES__RESTRICT stream, size_t max_length, - char *ES__RESTRICT *ES__RESTRICT line, - size_t *ES__RESTRICT line_length) -{ - size_t space_left; - size_t line_size; - estream_t line_stream; - char *line_new; - void *line_stream_cookie; - char *newline; - unsigned char *data; - size_t data_len; - int err; - es_syshd_t syshd; - - line_new = NULL; - line_stream = NULL; - line_stream_cookie = NULL; - - err = func_mem_create (&line_stream_cookie, NULL, 0, 0, - BUFFER_BLOCK_SIZE, 1, - mem_realloc, mem_free, - O_RDWR, - 0); - if (err) - goto out; - - memset (&syshd, 0, sizeof syshd); - err = es_create (&line_stream, line_stream_cookie, &syshd, - estream_functions_mem, O_RDWR, 1, 0); - if (err) - goto out; - - space_left = max_length; - line_size = 0; - while (1) - { - if (max_length && (space_left == 1)) - break; - - err = es_peek (stream, &data, &data_len); - if (err || (! data_len)) - break; - - if (data_len > (space_left - 1)) - data_len = space_left - 1; - - newline = memchr (data, '\n', data_len); - if (newline) - { - data_len = (newline - (char *) data) + 1; - err = es_write (line_stream, data, data_len, NULL); - if (! err) - { - space_left -= data_len; - line_size += data_len; - es_skip (stream, data_len); - break; - } - } - else - { - err = es_write (line_stream, data, data_len, NULL); - if (! err) - { - space_left -= data_len; - line_size += data_len; - es_skip (stream, data_len); - } - } - if (err) - break; - } - if (err) - goto out; - - /* Complete line has been written to line_stream. */ - - if ((max_length > 1) && (! line_size)) - { - stream->intern->indicators.eof = 1; - goto out; - } - - err = es_seek (line_stream, 0, SEEK_SET, NULL); - if (err) - goto out; - - if (! *line) - { - line_new = mem_alloc (line_size + 1); - if (! line_new) - { - err = -1; - goto out; - } - } - else - line_new = *line; - - err = es_read (line_stream, line_new, line_size, NULL); - if (err) - goto out; - - line_new[line_size] = '\0'; - - if (! *line) - *line = line_new; - if (line_length) - *line_length = line_size; - - out: - - if (line_stream) - do_close (line_stream, 0); - else if (line_stream_cookie) - es_func_mem_destroy (line_stream_cookie); - - if (err) - { - if (! *line) - mem_free (line_new); - stream->intern->indicators.err = 1; - } - - return err; -} - - -/* Output fucntion used for estream_format. */ -static int -print_writer (void *outfncarg, const char *buf, size_t buflen) -{ - estream_t stream = outfncarg; - size_t nwritten; - int rc; - - nwritten = 0; - rc = es_writen (stream, buf, buflen, &nwritten); - stream->intern->print_ntotal += nwritten; - return rc; -} - - -/* The core of our printf function. This is called in locked state. */ -static int -es_print (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, va_list ap) -{ - int rc; - - stream->intern->print_ntotal = 0; - rc = estream_format (print_writer, stream, format, ap); - if (rc) - return -1; - return (int)stream->intern->print_ntotal; -} - - -static void -es_set_indicators (estream_t stream, int ind_err, int ind_eof) -{ - if (ind_err != -1) - stream->intern->indicators.err = ind_err ? 1 : 0; - if (ind_eof != -1) - stream->intern->indicators.eof = ind_eof ? 1 : 0; -} - - -static int -es_get_indicator (estream_t stream, int ind_err, int ind_eof) -{ - int ret = 0; - - if (ind_err) - ret = stream->intern->indicators.err; - else if (ind_eof) - ret = stream->intern->indicators.eof; - - return ret; -} - - -static int -es_set_buffering (estream_t ES__RESTRICT stream, - char *ES__RESTRICT buffer, int mode, size_t size) -{ - int err; - - /* Flush or empty buffer depending on mode. */ - if (stream->flags.writing) - { - err = es_flush (stream); - if (err) - goto out; - } - else - es_empty (stream); - - es_set_indicators (stream, -1, 0); - - /* Free old buffer in case that was allocated by this function. */ - if (stream->intern->deallocate_buffer) - { - stream->intern->deallocate_buffer = 0; - mem_free (stream->buffer); - stream->buffer = NULL; - } - - if (mode == _IONBF) - stream->buffer_size = 0; - else - { - void *buffer_new; - - if (buffer) - buffer_new = buffer; - else - { - if (!size) - size = BUFSIZ; - buffer_new = mem_alloc (size); - if (! buffer_new) - { - err = -1; - goto out; - } - } - - stream->buffer = buffer_new; - stream->buffer_size = size; - if (! buffer) - stream->intern->deallocate_buffer = 1; - } - stream->intern->strategy = mode; - err = 0; - - out: - - return err; -} - - -static off_t -es_offset_calculate (estream_t stream) -{ - off_t offset; - - offset = stream->intern->offset + stream->data_offset; - if (offset < stream->unread_data_len) - /* Offset undefined. */ - offset = 0; - else - offset -= stream->unread_data_len; - - return offset; -} - - -static void -es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new, - void **ES__RESTRICT opaque_old) -{ - if (opaque_old) - *opaque_old = stream->intern->opaque; - if (opaque_new) - stream->intern->opaque = opaque_new; -} - - - - -/* API. */ - -int -es_init (void) -{ - int err; - - err = do_init (); - - return err; -} - - - -estream_t -es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) -{ - unsigned int modeflags, cmode; - int samethread, create_called; - estream_t stream; - void *cookie; - int err; - int fd; - es_syshd_t syshd; - - stream = NULL; - cookie = NULL; - create_called = 0; - - err = parse_mode (mode, &modeflags, &samethread, &cmode); - if (err) - goto out; - - err = func_file_create (&cookie, &fd, path, modeflags, cmode); - if (err) - goto out; - - syshd.type = ES_SYSHD_FD; - syshd.u.fd = fd; - - create_called = 1; - err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, - samethread, 0); - if (err) - goto out; - - if (stream && path) - fname_set_internal (stream, path, 1); - - out: - - if (err && create_called) - (*estream_functions_fd.func_close) (cookie); - - return stream; -} - - - -/* Create a new estream object in memory. If DATA is not NULL this - buffer will be used as the memory buffer; thus after this functions - returns with the success the the memory at DATA belongs to the new - estream. The allocated length of DATA is given by DATA_LEN and its - used length by DATA_N. Usually this is malloced buffer; if a - static buffer is provided, the caller must pass false for GROW and - provide a dummy function for FUNC_FREE. FUNC_FREE and FUNC_REALLOC - allow the caller to provide custom functions for realloc and free - to be used by the new estream object. Note that the realloc - function is also used for initial allocation. If DATA is NULL a - buffer is internally allocated; either using internal function or - those provide by the caller. It is an error to provide a realloc - function but no free function. Providing only a free function is - allowed as long as GROW is false. */ -estream_t -es_mopen (void *ES__RESTRICT data, size_t data_n, size_t data_len, - unsigned int grow, - func_realloc_t func_realloc, func_free_t func_free, - const char *ES__RESTRICT mode) -{ - int create_called = 0; - estream_t stream = NULL; - void *cookie = NULL; - unsigned int modeflags; - int samethread; - int err; - es_syshd_t syshd; - - err = parse_mode (mode, &modeflags, &samethread, NULL); - if (err) - goto out; - - err = func_mem_create (&cookie, data, data_n, data_len, - BUFFER_BLOCK_SIZE, grow, - func_realloc, func_free, modeflags, 0); - if (err) - goto out; - - memset (&syshd, 0, sizeof syshd); - create_called = 1; - err = es_create (&stream, cookie, &syshd, - estream_functions_mem, modeflags, samethread, 0); - - out: - - if (err && create_called) - (*estream_functions_mem.func_close) (cookie); - - return stream; -} - - - -estream_t -es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode) -{ - unsigned int modeflags; - int samethread; - estream_t stream = NULL; - void *cookie = NULL; - es_syshd_t syshd; - - /* Memory streams are always read/write. We use MODE only to get - the append flag. */ - if (parse_mode (mode, &modeflags, &samethread, NULL)) - return NULL; - modeflags |= O_RDWR; - - if (func_mem_create (&cookie, NULL, 0, 0, - BUFFER_BLOCK_SIZE, 1, - mem_realloc, mem_free, modeflags, - memlimit)) - return NULL; - - memset (&syshd, 0, sizeof syshd); - if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, - samethread, 0)) - (*estream_functions_mem.func_close) (cookie); - - if (stream) - stream->intern->func_ioctl = es_func_mem_ioctl; - - return stream; -} - - -/* This is the same as es_fopenmem but intializes the memory with a - copy of (DATA,DATALEN). The stream is initally set to the - beginning. If MEMLIMIT is not 0 but shorter than DATALEN it - DATALEN will be used as the value for MEMLIMIT. */ -estream_t -es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode, - const void *data, size_t datalen) -{ - estream_t stream; - - if (memlimit && memlimit < datalen) - memlimit = datalen; - - stream = es_fopenmem (memlimit, mode); - if (stream && data && datalen) - { - if (es_writen (stream, data, datalen, NULL)) - { - int saveerrno = errno; - es_fclose (stream); - stream = NULL; - _set_errno (saveerrno); - } - else - { - es_seek (stream, 0L, SEEK_SET, NULL); - es_set_indicators (stream, 0, 0); - } - } - return stream; -} - - - -estream_t -es_fopencookie (void *ES__RESTRICT cookie, - const char *ES__RESTRICT mode, - es_cookie_io_functions_t functions) -{ - unsigned int modeflags; - int samethread; - estream_t stream; - int err; - es_syshd_t syshd; - - stream = NULL; - modeflags = 0; - - err = parse_mode (mode, &modeflags, &samethread, NULL); - if (err) - goto out; - - memset (&syshd, 0, sizeof syshd); - err = es_create (&stream, cookie, &syshd, functions, modeflags, - samethread, 0); - if (err) - goto out; - - out: - return stream; -} - - - -estream_t -do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list) -{ - unsigned int modeflags; - int samethread, create_called; - estream_t stream; - void *cookie; - int err; - es_syshd_t syshd; - - stream = NULL; - cookie = NULL; - create_called = 0; - - err = parse_mode (mode, &modeflags, &samethread, NULL); - if (err) - goto out; - - err = func_fd_create (&cookie, filedes, modeflags, no_close); - if (err) - goto out; - - syshd.type = ES_SYSHD_FD; - syshd.u.fd = filedes; - create_called = 1; - err = es_create (&stream, cookie, &syshd, estream_functions_fd, - modeflags, samethread, with_locked_list); - - out: - if (err && create_called) - (*estream_functions_fd.func_close) (cookie); - - return stream; -} - -estream_t -es_fdopen (int filedes, const char *mode) -{ - return do_fdopen (filedes, mode, 0, 0); -} - -/* A variant of es_fdopen which does not close FILEDES at the end. */ -estream_t -es_fdopen_nc (int filedes, const char *mode) -{ - return do_fdopen (filedes, mode, 1, 0); -} - - - -estream_t -do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list) -{ - unsigned int modeflags, cmode; - int samethread, create_called; - estream_t stream; - void *cookie; - int err; - es_syshd_t syshd; - - stream = NULL; - cookie = NULL; - create_called = 0; - - err = parse_mode (mode, &modeflags, &samethread, &cmode); - if (err) - goto out; - - if (fp) - fflush (fp); - err = func_fp_create (&cookie, fp, modeflags, no_close); - if (err) - goto out; - - syshd.type = ES_SYSHD_FD; - syshd.u.fd = fp? fileno (fp): -1; - create_called = 1; - err = es_create (&stream, cookie, &syshd, estream_functions_fp, - modeflags, samethread, with_locked_list); - - out: - - if (err && create_called) - (*estream_functions_fp.func_close) (cookie); - - return stream; -} - - -/* Create an estream from the stdio stream FP. This mechanism is - useful in case the stdio streams have special properties and may - not be mixed with fd based functions. This is for example the case - under Windows where the 3 standard streams are associated with the - console whereas a duped and fd-opened stream of one of this stream - won't be associated with the console. As this messes things up it - is easier to keep on using the standard I/O stream as a backend for - estream. */ -estream_t -es_fpopen (FILE *fp, const char *mode) -{ - return do_fpopen (fp, mode, 0, 0); -} - - -/* Same as es_fpopen but does not close FP at the end. */ -estream_t -es_fpopen_nc (FILE *fp, const char *mode) -{ - return do_fpopen (fp, mode, 1, 0); -} - - - -#ifdef HAVE_W32_SYSTEM -estream_t -do_w32open (HANDLE hd, const char *mode, - int no_close, int with_locked_list) -{ - unsigned int modeflags, cmode; - int samethread; - int create_called = 0; - estream_t stream = NULL; - void *cookie = NULL; - int err; - es_syshd_t syshd; - - err = parse_mode (mode, &modeflags, &samethread, &cmode); - if (err) - goto leave; - - err = es_func_w32_create (&cookie, hd, modeflags, no_close); - if (err) - goto leave; - - syshd.type = ES_SYSHD_HANDLE; - syshd.u.handle = hd; - create_called = 1; - err = es_create (&stream, cookie, &syshd, estream_functions_w32, - modeflags, samethread, with_locked_list); - - leave: - if (err && create_called) - (*estream_functions_w32.func_close) (cookie); - - return stream; -} -#endif /*HAVE_W32_SYSTEM*/ - -static estream_t -do_sysopen (es_syshd_t *syshd, const char *mode, int no_close) -{ - estream_t stream; - - switch (syshd->type) - { - case ES_SYSHD_FD: - case ES_SYSHD_SOCK: - stream = do_fdopen (syshd->u.fd, mode, no_close, 0); - break; - -#ifdef HAVE_W32_SYSTEM - case ES_SYSHD_HANDLE: - stream = do_w32open (syshd->u.handle, mode, no_close, 0); - break; -#endif - - /* FIXME: Support RVIDs under Wince? */ - - default: - _set_errno (EINVAL); - stream = NULL; - } - return stream; -} - -/* On POSIX systems this function is an alias for es_fdopen. Under - Windows it uses the bare W32 API and thus a HANDLE instead of a - file descriptor. */ -estream_t -es_sysopen (es_syshd_t *syshd, const char *mode) -{ - return do_sysopen (syshd, mode, 0); -} - -/* Same as es_sysopen but the handle/fd will not be closed by - es_fclose. */ -estream_t -es_sysopen_nc (es_syshd_t *syshd, const char *mode) -{ - return do_sysopen (syshd, mode, 1); -} - - - -/* Set custom standard descriptors to be used for stdin, stdout and - stderr. This function needs to be called before any of the - standard streams are accessed. */ -void -_es_set_std_fd (int no, int fd) -{ - /* fprintf (stderr, "es_set_std_fd(%d, %d)\n", no, fd); */ - lock_list (); - if (no >= 0 && no < 3 && !custom_std_fds_valid[no]) - { - custom_std_fds[no] = fd; - custom_std_fds_valid[no] = 1; - } - unlock_list (); -} - - -/* Return the stream used for stdin, stdout or stderr. */ -estream_t -_es_get_std_stream (int fd) -{ - estream_list_t list_obj; - estream_t stream = NULL; - - fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */ - - lock_list (); - - for (list_obj = estream_list; list_obj; list_obj = list_obj->next) - if (list_obj->stream && list_obj->stream->intern->is_stdstream - && list_obj->stream->intern->stdstream_fd == fd) - { - stream = list_obj->stream; - break; - } - if (!stream) - { - /* Standard stream not yet created. We first try to create them - from registered file descriptors. */ - if (!fd && custom_std_fds_valid[0]) - stream = do_fdopen (custom_std_fds[0], "r", 1, 1); - else if (fd == 1 && custom_std_fds_valid[1]) - stream = do_fdopen (custom_std_fds[1], "a", 1, 1); - else if (custom_std_fds_valid[2]) - stream = do_fdopen (custom_std_fds[2], "a", 1, 1); - - if (!stream) - { - /* Second try is to use the standard C streams. */ - if (!fd) - stream = do_fpopen (stdin, "r", 1, 1); - else if (fd == 1) - stream = do_fpopen (stdout, "a", 1, 1); - else - stream = do_fpopen (stderr, "a", 1, 1); - } - - if (!stream) - { - /* Last try: Create a bit bucket. */ - stream = do_fpopen (NULL, fd? "a":"r", 0, 1); - if (!stream) - { - fprintf (stderr, "fatal: error creating a dummy estream" - " for %d: %s\n", fd, strerror (errno)); - abort(); - } - } - - stream->intern->is_stdstream = 1; - stream->intern->stdstream_fd = fd; - if (fd == 2) - es_set_buffering (stream, NULL, _IOLBF, 0); - fname_set_internal (stream, - fd == 0? "[stdin]" : - fd == 1? "[stdout]" : "[stderr]", 0); - } - - unlock_list (); - return stream; -} - -/* Note: A "samethread" keyword given in "mode" is ignored and the - value used by STREAM is used instead. */ -estream_t -es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, - estream_t ES__RESTRICT stream) -{ - int err; - - if (path) - { - unsigned int modeflags, cmode; - int dummy, samethread, create_called; - void *cookie; - int fd; - es_syshd_t syshd; - - cookie = NULL; - create_called = 0; - - samethread = stream->intern->samethread; - - lock_stream (stream); - - es_deinitialize (stream); - - err = parse_mode (mode, &modeflags, &dummy, &cmode); - if (err) - goto leave; - (void)dummy; - - err = func_file_create (&cookie, &fd, path, modeflags, cmode); - if (err) - goto leave; - - syshd.type = ES_SYSHD_FD; - syshd.u.fd = fd; - create_called = 1; - init_stream_obj (stream, cookie, &syshd, estream_functions_fd, - modeflags, samethread); - - leave: - - if (err) - { - if (create_called) - es_func_fd_destroy (cookie); - - do_close (stream, 0); - stream = NULL; - } - else - { - if (path) - fname_set_internal (stream, path, 1); - unlock_stream (stream); - } - } - else - { - /* FIXME? We don't support re-opening at the moment. */ - _set_errno (EINVAL); - es_deinitialize (stream); - do_close (stream, 0); - stream = NULL; - } - - return stream; -} - - -int -es_fclose (estream_t stream) -{ - int err; - - err = do_close (stream, 0); - - return err; -} - - -/* This is a special version of es_fclose which can be used with - es_fopenmem to return the memory buffer. This is feature is useful - to write to a memory buffer using estream. Note that the function - does not close the stream if the stream does not support snatching - the buffer. On error NULL is stored at R_BUFFER. Note that if no - write operation has happened, NULL may also be stored at BUFFER on - success. The caller needs to release the returned memory using - es_free. */ -int -es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen) -{ - int err; - - /* Note: There is no need to lock the stream in a close call. The - object will be destroyed after the close and thus any other - contender for the lock would work on a closed stream. */ - - if (r_buffer) - { - cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl; - size_t buflen; - - *r_buffer = NULL; - - if (!func_ioctl) - { - _set_errno (EOPNOTSUPP); - err = -1; - goto leave; - } - - if (stream->flags.writing) - { - err = es_flush (stream); - if (err) - goto leave; - stream->flags.writing = 0; - } - - err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER, - r_buffer, &buflen); - if (err) - goto leave; - if (r_buflen) - *r_buflen = buflen; - } - - err = do_close (stream, 0); - - leave: - if (err && r_buffer) - { - mem_free (*r_buffer); - *r_buffer = NULL; - } - return err; -} - - -/* Register or unregister a close notification function for STREAM. - FNC is the function to call and FNC_VALUE the value passed as - second argument. To register the notification the value for MODE - must be 1. If mode is 0 the function tries to remove or disable an - already registered notification; for this to work the value of FNC - and FNC_VALUE must be the same as with the registration and - FNC_VALUE must be a unique value. No error will be returned if - MODE is 0. - - FIXME: I think the next comment is not anymore correct: - Unregister should only be used in the error case because it may not - be able to remove memory internally allocated for the onclose - handler. - - FIXME: Unregister is not thread safe. - - The notification will be called right before the stream is closed. - It may not call any estream function for STREAM, neither direct nor - indirectly. */ -int -es_onclose (estream_t stream, int mode, - void (*fnc) (estream_t, void*), void *fnc_value) -{ - int err; - - lock_stream (stream); - err = do_onclose (stream, mode, fnc, fnc_value); - unlock_stream (stream); - - return err; -} - - -int -es_fileno_unlocked (estream_t stream) -{ - es_syshd_t syshd; - - if (es_syshd_unlocked (stream, &syshd)) - return -1; - switch (syshd.type) - { - case ES_SYSHD_FD: return syshd.u.fd; - case ES_SYSHD_SOCK: return syshd.u.sock; - default: - _set_errno (EINVAL); - return -1; - } -} - - -/* Return the handle of a stream which has been opened by es_sysopen. - The caller needs to pass a structure which will be filled with the - sys handle. Return 0 on success or true on error and sets errno. - This is the unlocked version. */ -int -es_syshd_unlocked (estream_t stream, es_syshd_t *syshd) -{ - if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE) - { - if (syshd) - syshd->type = ES_SYSHD_NONE; - _set_errno (EINVAL); - return -1; - } - - *syshd = stream->intern->syshd; - return 0; -} - - -void -es_flockfile (estream_t stream) -{ - lock_stream (stream); -} - - -int -es_ftrylockfile (estream_t stream) -{ - return trylock_stream (stream); -} - - -void -es_funlockfile (estream_t stream) -{ - unlock_stream (stream); -} - - -int -es_fileno (estream_t stream) -{ - int ret; - - lock_stream (stream); - ret = es_fileno_unlocked (stream); - unlock_stream (stream); - - return ret; -} - - -/* Return the handle of a stream which has been opened by es_sysopen. - The caller needs to pass a structure which will be filled with the - sys handle. Return 0 on success or true on error and sets errno. - This is the unlocked version. */ -int -es_syshd (estream_t stream, es_syshd_t *syshd) -{ - int ret; - - lock_stream (stream); - ret = es_syshd_unlocked (stream, syshd); - unlock_stream (stream); - - return ret; -} - - -int -es_feof_unlocked (estream_t stream) -{ - return es_get_indicator (stream, 0, 1); -} - - -int -es_feof (estream_t stream) -{ - int ret; - - lock_stream (stream); - ret = es_feof_unlocked (stream); - unlock_stream (stream); - - return ret; -} - - -int -es_ferror_unlocked (estream_t stream) -{ - return es_get_indicator (stream, 1, 0); -} - - -int -es_ferror (estream_t stream) -{ - int ret; - - lock_stream (stream); - ret = es_ferror_unlocked (stream); - unlock_stream (stream); - - return ret; -} - - -void -es_clearerr_unlocked (estream_t stream) -{ - es_set_indicators (stream, 0, 0); -} - - -void -es_clearerr (estream_t stream) -{ - lock_stream (stream); - es_clearerr_unlocked (stream); - unlock_stream (stream); -} - - -static int -do_fflush (estream_t stream) -{ - int err; - - if (stream->flags.writing) - err = es_flush (stream); - else - { - es_empty (stream); - err = 0; - } - - return err; -} - - -int -es_fflush (estream_t stream) -{ - int err; - - if (stream) - { - lock_stream (stream); - err = do_fflush (stream); - unlock_stream (stream); - } - else - { - estream_list_t item; - - err = 0; - lock_list (); - for (item = estream_list; item; item = item->next) - if (item->stream) - { - lock_stream (item->stream); - err |= do_fflush (item->stream); - unlock_stream (item->stream); - } - unlock_list (); - } - return err ? EOF : 0; -} - - -int -es_fseek (estream_t stream, long int offset, int whence) -{ - int err; - - lock_stream (stream); - err = es_seek (stream, offset, whence, NULL); - unlock_stream (stream); - - return err; -} - - -int -es_fseeko (estream_t stream, off_t offset, int whence) -{ - int err; - - lock_stream (stream); - err = es_seek (stream, offset, whence, NULL); - unlock_stream (stream); - - return err; -} - - -long int -es_ftell (estream_t stream) -{ - long int ret; - - lock_stream (stream); - ret = es_offset_calculate (stream); - unlock_stream (stream); - - return ret; -} - - -off_t -es_ftello (estream_t stream) -{ - off_t ret = -1; - - lock_stream (stream); - ret = es_offset_calculate (stream); - unlock_stream (stream); - - return ret; -} - - -void -es_rewind (estream_t stream) -{ - lock_stream (stream); - es_seek (stream, 0L, SEEK_SET, NULL); - es_set_indicators (stream, 0, -1); - unlock_stream (stream); -} - - -int -_es_getc_underflow (estream_t stream) -{ - int err; - unsigned char c; - size_t bytes_read; - - err = es_readn (stream, &c, 1, &bytes_read); - - return (err || (! bytes_read)) ? EOF : c; -} - - -int -_es_putc_overflow (int c, estream_t stream) -{ - unsigned char d = c; - int err; - - err = es_writen (stream, &d, 1, NULL); - - return err ? EOF : c; -} - - -int -es_fgetc (estream_t stream) -{ - int ret; - - lock_stream (stream); - ret = es_getc_unlocked (stream); - unlock_stream (stream); - - return ret; -} - - -int -es_fputc (int c, estream_t stream) -{ - int ret; - - lock_stream (stream); - ret = es_putc_unlocked (c, stream); - unlock_stream (stream); - - return ret; -} - - -int -es_ungetc (int c, estream_t stream) -{ - unsigned char data = (unsigned char) c; - size_t data_unread; - - lock_stream (stream); - es_unreadn (stream, &data, 1, &data_unread); - unlock_stream (stream); - - return data_unread ? c : EOF; -} - - -int -es_read (estream_t ES__RESTRICT stream, - void *ES__RESTRICT buffer, size_t bytes_to_read, - size_t *ES__RESTRICT bytes_read) -{ - int err; - - if (bytes_to_read) - { - lock_stream (stream); - err = es_readn (stream, buffer, bytes_to_read, bytes_read); - unlock_stream (stream); - } - else - err = 0; - - return err; -} - - -int -es_write (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, size_t bytes_to_write, - size_t *ES__RESTRICT bytes_written) -{ - int err; - - if (bytes_to_write) - { - lock_stream (stream); - err = es_writen (stream, buffer, bytes_to_write, bytes_written); - unlock_stream (stream); - } - else - err = 0; - - return err; -} - - -size_t -es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems, - estream_t ES__RESTRICT stream) -{ - size_t ret, bytes; - - if (size * nitems) - { - lock_stream (stream); - es_readn (stream, ptr, size * nitems, &bytes); - unlock_stream (stream); - - ret = bytes / size; - } - else - ret = 0; - - return ret; -} - - -size_t -es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems, - estream_t ES__RESTRICT stream) -{ - size_t ret, bytes; - - if (size * nitems) - { - lock_stream (stream); - es_writen (stream, ptr, size * nitems, &bytes); - unlock_stream (stream); - - ret = bytes / size; - } - else - ret = 0; - - return ret; -} - - -char * -es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream) -{ - unsigned char *s = (unsigned char*)buffer; - int c; - - if (!length) - return NULL; - - c = EOF; - lock_stream (stream); - while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n') - { - *s++ = c; - length--; - } - unlock_stream (stream); - - if (c == EOF && s == (unsigned char*)buffer) - return NULL; /* Nothing read. */ - - if (c != EOF && length > 1) - *s++ = c; - - *s = 0; - return buffer; -} - - -int -es_fputs_unlocked (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream) -{ - size_t length; - int err; - - length = strlen (s); - err = es_writen (stream, s, length, NULL); - return err ? EOF : 0; -} - -int -es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream) -{ - size_t length; - int err; - - length = strlen (s); - lock_stream (stream); - err = es_writen (stream, s, length, NULL); - unlock_stream (stream); - - return err ? EOF : 0; -} - - -ssize_t -es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n, - estream_t ES__RESTRICT stream) -{ - char *line = NULL; - size_t line_n = 0; - int err; - - lock_stream (stream); - err = doreadline (stream, 0, &line, &line_n); - unlock_stream (stream); - if (err) - goto out; - - if (*n) - { - /* Caller wants us to use his buffer. */ - - if (*n < (line_n + 1)) - { - /* Provided buffer is too small -> resize. */ - - void *p; - - p = mem_realloc (*lineptr, line_n + 1); - if (! p) - err = -1; - else - { - if (*lineptr != p) - *lineptr = p; - } - } - - if (! err) - { - memcpy (*lineptr, line, line_n + 1); - if (*n != line_n) - *n = line_n; - } - mem_free (line); - } - else - { - /* Caller wants new buffers. */ - *lineptr = line; - *n = line_n; - } - - out: - - return err ? err : (ssize_t)line_n; -} - - - -/* Same as fgets() but if the provided buffer is too short a larger - one will be allocated. This is similar to getline. A line is - considered a byte stream ending in a LF. - - If MAX_LENGTH is not NULL, it shall point to a value with the - maximum allowed allocation. - - Returns the length of the line. EOF is indicated by a line of - length zero. A truncated line is indicated my setting the value at - MAX_LENGTH to 0. If the returned value is less then 0 not enough - memory was enable or another error occurred; ERRNO is then set - accordingly. - - If a line has been truncated, the file pointer is moved forward to - the end of the line so that the next read starts with the next - line. Note that MAX_LENGTH must be re-initialzied in this case. - - The caller initially needs to provide the address of a variable, - initialized to NULL, at ADDR_OF_BUFFER and don't change this value - anymore with the following invocations. LENGTH_OF_BUFFER should be - the address of a variable, initialized to 0, which is also - maintained by this function. Thus, both paramaters should be - considered the state of this function. - - Note: The returned buffer is allocated with enough extra space to - allow the caller to append a CR,LF,Nul. The buffer should be - released using es_free. - */ -ssize_t -es_read_line (estream_t stream, - char **addr_of_buffer, size_t *length_of_buffer, - size_t *max_length) -{ - int c; - char *buffer = *addr_of_buffer; - size_t length = *length_of_buffer; - size_t nbytes = 0; - size_t maxlen = max_length? *max_length : 0; - char *p; - - if (!buffer) - { - /* No buffer given - allocate a new one. */ - length = 256; - buffer = mem_alloc (length); - *addr_of_buffer = buffer; - if (!buffer) - { - *length_of_buffer = 0; - if (max_length) - *max_length = 0; - return -1; - } - *length_of_buffer = length; - } - - if (length < 4) - { - /* This should never happen. If it does, the function has been - called with wrong arguments. */ - _set_errno (EINVAL); - return -1; - } - length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */ - - lock_stream (stream); - p = buffer; - while ((c = es_getc_unlocked (stream)) != EOF) - { - if (nbytes == length) - { - /* Enlarge the buffer. */ - if (maxlen && length > maxlen) - { - /* We are beyond our limit: Skip the rest of the line. */ - while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF) - ; - *p++ = '\n'; /* Always append a LF (we reserved some space). */ - nbytes++; - if (max_length) - *max_length = 0; /* Indicate truncation. */ - break; /* the while loop. */ - } - length += 3; /* Adjust for the reserved bytes. */ - length += length < 1024? 256 : 1024; - *addr_of_buffer = mem_realloc (buffer, length); - if (!*addr_of_buffer) - { - int save_errno = errno; - mem_free (buffer); - *length_of_buffer = 0; - if (max_length) - *max_length = 0; - unlock_stream (stream); - _set_errno (save_errno); - return -1; - } - buffer = *addr_of_buffer; - *length_of_buffer = length; - length -= 3; - p = buffer + nbytes; - } - *p++ = c; - nbytes++; - if (c == '\n') - break; - } - *p = 0; /* Make sure the line is a string. */ - unlock_stream (stream); - - return nbytes; -} - -/* Wrapper around free() to match the memory allocation system used - by estream. Should be used for all buffers returned to the caller - by libestream. */ -void -es_free (void *a) -{ - mem_free (a); -} - - -int -es_vfprintf_unlocked (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, - va_list ap) -{ - return es_print (stream, format, ap); -} - - -int -es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format, - va_list ap) -{ - int ret; - - lock_stream (stream); - ret = es_print (stream, format, ap); - unlock_stream (stream); - - return ret; -} - - -int -es_fprintf_unlocked (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, ...) -{ - int ret; - - va_list ap; - va_start (ap, format); - ret = es_print (stream, format, ap); - va_end (ap); - - return ret; -} - - -int -es_fprintf (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, ...) -{ - int ret; - - va_list ap; - va_start (ap, format); - lock_stream (stream); - ret = es_print (stream, format, ap); - unlock_stream (stream); - va_end (ap); - - return ret; -} - - -int -es_printf_unlocked (const char *ES__RESTRICT format, ...) -{ - int ret; - - va_list ap; - va_start (ap, format); - ret = es_print (es_stdout, format, ap); - va_end (ap); - - return ret; -} - - -int -es_printf (const char *ES__RESTRICT format, ...) -{ - int ret; - estream_t stream = es_stdout; - - va_list ap; - va_start (ap, format); - lock_stream (stream); - ret = es_print (stream, format, ap); - unlock_stream (stream); - va_end (ap); - - return ret; -} - - -/* A variant of asprintf. The function returns the allocated buffer - or NULL on error; ERRNO is set in the error case. The caller - should use es_free to release the buffer. This function actually - belongs into estream-printf but we put it here as a convenience - and because es_free is required anyway. */ -char * -es_asprintf (const char *ES__RESTRICT format, ...) -{ - int rc; - va_list ap; - char *buf; - - va_start (ap, format); - rc = estream_vasprintf (&buf, format, ap); - va_end (ap); - if (rc < 0) - return NULL; - return buf; -} - - -/* A variant of vasprintf. The function returns the allocated buffer - or NULL on error; ERRNO is set in the error case. The caller - should use es_free to release the buffer. This function actually - belongs into estream-printf but we put it here as a convenience - and because es_free is required anyway. */ -char * -es_vasprintf (const char *ES__RESTRICT format, va_list ap) -{ - int rc; - char *buf; - - rc = estream_vasprintf (&buf, format, ap); - if (rc < 0) - return NULL; - return buf; -} - - -static int -tmpfd (void) -{ -#ifdef HAVE_W32_SYSTEM - int attempts, n; -#ifdef HAVE_W32CE_SYSTEM - wchar_t buffer[MAX_PATH+9+12+1]; -# define mystrlen(a) wcslen (a) - wchar_t *name, *p; -#else - char buffer[MAX_PATH+9+12+1]; -# define mystrlen(a) strlen (a) - char *name, *p; -#endif - HANDLE file; - int pid = GetCurrentProcessId (); - unsigned int value; - int i; - - n = GetTempPath (MAX_PATH+1, buffer); - if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH) - { - _set_errno (ENOENT); - return -1; - } - p = buffer + mystrlen (buffer); -#ifdef HAVE_W32CE_SYSTEM - wcscpy (p, L"_estream"); -#else - strcpy (p, "_estream"); -#endif - p += 8; - /* We try to create the directory but don't care about an error as - it may already exist and the CreateFile would throw an error - anyway. */ - CreateDirectory (buffer, NULL); - *p++ = '\\'; - name = p; - for (attempts=0; attempts < 10; attempts++) - { - p = name; - value = (GetTickCount () ^ ((pid<<16) & 0xffff0000)); - for (i=0; i < 8; i++) - { - *p++ = tohex (((value >> 28) & 0x0f)); - value <<= 4; - } -#ifdef HAVE_W32CE_SYSTEM - wcscpy (p, L".tmp"); -#else - strcpy (p, ".tmp"); -#endif - file = CreateFile (buffer, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - CREATE_NEW, - FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); - if (file != INVALID_HANDLE_VALUE) - { -#ifdef HAVE_W32CE_SYSTEM - int fd = (int)file; -#else - int fd = _open_osfhandle ((long)file, 0); - if (fd == -1) - { - CloseHandle (file); - return -1; - } -#endif - return fd; - } - Sleep (1); /* One ms as this is the granularity of GetTickCount. */ - } - _set_errno (ENOENT); - return -1; -#else /*!HAVE_W32_SYSTEM*/ - FILE *fp; - int fp_fd; - int fd; - - fp = NULL; - fd = -1; - - fp = tmpfile (); - if (! fp) - goto out; - - fp_fd = fileno (fp); - fd = dup (fp_fd); - - out: - - if (fp) - fclose (fp); - - return fd; -#endif /*!HAVE_W32_SYSTEM*/ -} - -estream_t -es_tmpfile (void) -{ - unsigned int modeflags; - int create_called; - estream_t stream; - void *cookie; - int err; - int fd; - es_syshd_t syshd; - - create_called = 0; - stream = NULL; - modeflags = O_RDWR | O_TRUNC | O_CREAT; - cookie = NULL; - - fd = tmpfd (); - if (fd == -1) - { - err = -1; - goto out; - } - - err = func_fd_create (&cookie, fd, modeflags, 0); - if (err) - goto out; - - syshd.type = ES_SYSHD_FD; - syshd.u.fd = fd; - create_called = 1; - err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, - 0, 0); - - out: - if (err) - { - if (create_called) - es_func_fd_destroy (cookie); - else if (fd != -1) - close (fd); - stream = NULL; - } - - return stream; -} - - -int -es_setvbuf (estream_t ES__RESTRICT stream, - char *ES__RESTRICT buf, int type, size_t size) -{ - int err; - - if ((type == _IOFBF || type == _IOLBF || type == _IONBF) - && (!buf || size || type == _IONBF)) - { - lock_stream (stream); - err = es_set_buffering (stream, buf, type, size); - unlock_stream (stream); - } - else - { - _set_errno (EINVAL); - err = -1; - } - - return err; -} - - -void -es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf) -{ - lock_stream (stream); - es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); - unlock_stream (stream); -} - - -/* Put a stream into binary mode. This is only needed for the - standard streams if they are to be used in a binary way. On Unix - systems it is never needed but MSDOS based systems require such a - call. It needs to be called before any I/O is done on STREAM. */ -void -es_set_binary (estream_t stream) -{ - lock_stream (stream); - if (!(stream->intern->modeflags & O_BINARY)) - { - stream->intern->modeflags |= O_BINARY; -#ifdef HAVE_DOSISH_SYSTEM - if (stream->intern->func_read == es_func_fd_read) - { - estream_cookie_fd_t fd_cookie = stream->intern->cookie; - - if (!IS_INVALID_FD (fd_cookie->fd)) - setmode (fd_cookie->fd, O_BINARY); - } - else if (stream->intern->func_read == es_func_fp_read) - { - estream_cookie_fp_t fp_cookie = stream->intern->cookie; - - if (fp_cookie->fp) - setmode (fileno (fp_cookie->fp), O_BINARY); - } -#endif - } - unlock_stream (stream); -} - - -void -es_opaque_set (estream_t stream, void *opaque) -{ - lock_stream (stream); - es_opaque_ctrl (stream, opaque, NULL); - unlock_stream (stream); -} - - -void * -es_opaque_get (estream_t stream) -{ - void *opaque; - - lock_stream (stream); - es_opaque_ctrl (stream, NULL, &opaque); - unlock_stream (stream); - - return opaque; -} - - -static void -fname_set_internal (estream_t stream, const char *fname, int quote) -{ - if (stream->intern->printable_fname - && !stream->intern->printable_fname_inuse) - { - mem_free (stream->intern->printable_fname); - stream->intern->printable_fname = NULL; - } - if (stream->intern->printable_fname) - return; /* Can't change because it is in use. */ - - if (*fname != '[') - quote = 0; - else - quote = !!quote; - - stream->intern->printable_fname = mem_alloc (strlen (fname) + quote + 1); - if (fname) - { - if (quote) - stream->intern->printable_fname[0] = '\\'; - strcpy (stream->intern->printable_fname+quote, fname); - } -} - - -/* Set the filename attribute of STREAM. There is no error return. - as long as STREAM is valid. This function is called internally by - functions which open a filename. */ -void -es_fname_set (estream_t stream, const char *fname) -{ - if (fname) - { - lock_stream (stream); - fname_set_internal (stream, fname, 1); - unlock_stream (stream); - } -} - - -/* Return the filename attribute of STREAM. In case no filename has - been set, "[?]" will be returned. The returned file name is valid - as long as STREAM is valid. */ -const char * -es_fname_get (estream_t stream) -{ - const char *fname; - - lock_stream (stream); - fname = stream->intern->printable_fname; - if (fname) - stream->intern->printable_fname_inuse = 1; - unlock_stream (stream); - if (!fname) - fname = "[?]"; - return fname; -} - - -/* Print a BUFFER to STREAM while replacing all control characters and - the characters in DELIMITERS by standard C escape sequences. - Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL - the number of bytes actually written are stored at this - address. */ -int -es_write_sanitized (estream_t ES__RESTRICT stream, - const void * ES__RESTRICT buffer, size_t length, - const char * delimiters, - size_t * ES__RESTRICT bytes_written) -{ - const unsigned char *p = buffer; - size_t count = 0; - int ret; - - lock_stream (stream); - for (; length; length--, p++, count++) - { - if (*p < 0x20 - || *p == 0x7f - || (delimiters - && (strchr (delimiters, *p) || *p == '\\'))) - { - es_putc_unlocked ('\\', stream); - count++; - if (*p == '\n') - { - es_putc_unlocked ('n', stream); - count++; - } - else if (*p == '\r') - { - es_putc_unlocked ('r', stream); - count++; - } - else if (*p == '\f') - { - es_putc_unlocked ('f', stream); - count++; - } - else if (*p == '\v') - { - es_putc_unlocked ('v', stream); - count++; - } - else if (*p == '\b') - { - es_putc_unlocked ('b', stream); - count++; - } - else if (!*p) - { - es_putc_unlocked('0', stream); - count++; - } - else - { - es_fprintf_unlocked (stream, "x%02x", *p); - count += 3; - } - } - else - { - es_putc_unlocked (*p, stream); - count++; - } - } - - if (bytes_written) - *bytes_written = count; - ret = es_ferror_unlocked (stream)? -1 : 0; - unlock_stream (stream); - - return ret; -} - - -/* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string. - RESERVED must be 0. Returns 0 on success or -1 on error. If - BYTES_WRITTEN is not NULL the number of bytes actually written are - stored at this address. */ -int -es_write_hexstring (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, size_t length, - int reserved, size_t *ES__RESTRICT bytes_written ) -{ - int ret; - const unsigned char *s; - size_t count = 0; - - (void)reserved; - -#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) - - if (!length) - return 0; - - lock_stream (stream); - - for (s = buffer; length; s++, length--) - { - es_putc_unlocked ( tohex ((*s>>4)&15), stream); - es_putc_unlocked ( tohex (*s&15), stream); - count += 2; - } - - if (bytes_written) - *bytes_written = count; - ret = es_ferror_unlocked (stream)? -1 : 0; - - unlock_stream (stream); - - return ret; - -#undef tohex -} - - - -#ifdef GNUPG_MAJOR_VERSION -/* Special estream function to print an UTF8 string in the native - encoding. The interface is the same as es_write_sanitized, however - only one delimiter may be supported. - - THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */ -int -es_write_sanitized_utf8_buffer (estream_t stream, - const void *buffer, size_t length, - const char *delimiters, size_t *bytes_written) -{ - const char *p = buffer; - size_t i; - - /* We can handle plain ascii simpler, so check for it first. */ - for (i=0; i < length; i++ ) - { - if ( (p[i] & 0x80) ) - break; - } - if (i < length) - { - int delim = delimiters? *delimiters : 0; - char *buf; - int ret; - - /*(utf8 conversion already does the control character quoting). */ - buf = utf8_to_native (p, length, delim); - if (bytes_written) - *bytes_written = strlen (buf); - ret = es_fputs (buf, stream); - xfree (buf); - return ret == EOF? ret : (int)i; - } - else - return es_write_sanitized (stream, p, length, delimiters, bytes_written); -} -#endif /*GNUPG_MAJOR_VERSION*/ diff --git a/common/estream.h b/common/estream.h deleted file mode 100644 index 9b56cf10c..000000000 --- a/common/estream.h +++ /dev/null @@ -1,434 +0,0 @@ -/* estream.h - Extended stream I/O Library - * Copyright (C) 2004, 2005, 2006, 2007, 2010, 2011 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. - */ - -#ifndef ESTREAM_H -#define ESTREAM_H - -#include <sys/types.h> -#include <stdarg.h> -#include <stdio.h> - -/* To use this file with libraries the following macro is useful: - - #define _ESTREAM_EXT_SYM_PREFIX _foo_ - - This prefixes all external symbols with "_foo_". - - */ - - -#ifdef _ESTREAM_EXT_SYM_PREFIX -#ifndef _ESTREAM_PREFIX -#define _ESTREAM_PREFIX1(x,y) x ## y -#define _ESTREAM_PREFIX2(x,y) _ESTREAM_PREFIX1(x,y) -#define _ESTREAM_PREFIX(x) _ESTREAM_PREFIX2(_ESTREAM_EXT_SYM_PREFIX,x) -#endif /*_ESTREAM_PREFIX*/ -#define es_fopen _ESTREAM_PREFIX(es_fopen) -#define es_mopen _ESTREAM_PREFIX(es_mopen) -#define es_fopenmem _ESTREAM_PREFIX(es_fopenmem) -#define es_fopenmem_init _ESTREAM_PREFIX(es_fopenmem_init) -#define es_fdopen _ESTREAM_PREFIX(es_fdopen) -#define es_fdopen_nc _ESTREAM_PREFIX(es_fdopen_nc) -#define es_sysopen _ESTREAM_PREFIX(es_sysopen) -#define es_sysopen_nc _ESTREAM_PREFIX(es_sysopen_nc) -#define es_fpopen _ESTREAM_PREFIX(es_fpopen) -#define es_fpopen_nc _ESTREAM_PREFIX(es_fpopen_nc) -#define _es_set_std_fd _ESTREAM_PREFIX(_es_set_std_fd) -#define _es_get_std_stream _ESTREAM_PREFIX(_es_get_std_stream) -#define es_freopen _ESTREAM_PREFIX(es_freopen) -#define es_fopencookie _ESTREAM_PREFIX(es_fopencookie) -#define es_fclose _ESTREAM_PREFIX(es_fclose) -#define es_fclose_snatch _ESTREAM_PREFIX(es_fclose_snatch) -#define es_onclose _ESTREAM_PREFIX(es_onclose) -#define es_fileno _ESTREAM_PREFIX(es_fileno) -#define es_fileno_unlocked _ESTREAM_PREFIX(es_fileno_unlocked) -#define es_flockfile _ESTREAM_PREFIX(es_flockfile) -#define es_ftrylockfile _ESTREAM_PREFIX(es_ftrylockfile) -#define es_funlockfile _ESTREAM_PREFIX(es_funlockfile) -#define es_feof _ESTREAM_PREFIX(es_feof) -#define es_feof_unlocked _ESTREAM_PREFIX(es_feof_unlocked) -#define es_ferror _ESTREAM_PREFIX(es_ferror) -#define es_ferror_unlocked _ESTREAM_PREFIX(es_ferror_unlocked) -#define es_clearerr _ESTREAM_PREFIX(es_clearerr) -#define es_clearerr_unlocked _ESTREAM_PREFIX(es_clearerr_unlocked) -#define es_fflush _ESTREAM_PREFIX(es_fflush) -#define es_fseek _ESTREAM_PREFIX(es_fseek) -#define es_fseeko _ESTREAM_PREFIX(es_fseeko) -#define es_ftell _ESTREAM_PREFIX(es_ftell) -#define es_ftello _ESTREAM_PREFIX(es_ftello) -#define es_rewind _ESTREAM_PREFIX(es_rewind) -#define es_fgetc _ESTREAM_PREFIX(es_fgetc) -#define es_fputc _ESTREAM_PREFIX(es_fputc) -#define _es_getc_underflow _ESTREAM_PREFIX(_es_getc_underflow) -#define _es_putc_overflow _ESTREAM_PREFIX(_es_putc_overflow) -#define es_ungetc _ESTREAM_PREFIX(es_ungetc) -#define es_read _ESTREAM_PREFIX(es_read) -#define es_write _ESTREAM_PREFIX(es_write) -#define es_write_sanitized _ESTREAM_PREFIX(es_write_sanitized) -#define es_write_hexstring _ESTREAM_PREFIX(es_write_hexstring) -#define es_fread _ESTREAM_PREFIX(es_fread) -#define es_fwrite _ESTREAM_PREFIX(es_fwrite) -#define es_fgets _ESTREAM_PREFIX(es_fgets) -#define es_fputs _ESTREAM_PREFIX(es_fputs) -#define es_fputs_unlocked _ESTREAM_PREFIX(es_fputs_unlocked) -#define es_getline _ESTREAM_PREFIX(es_getline) -#define es_read_line _ESTREAM_PREFIX(es_read_line) -#define es_free _ESTREAM_PREFIX(es_free) -#define es_fprintf _ESTREAM_PREFIX(es_fprintf) -#define es_fprintf_unlocked _ESTREAM_PREFIX(es_fprintf_unlocked) -#define es_printf _ESTREAM_PREFIX(es_printf) -#define es_printf_unlocked _ESTREAM_PREFIX(es_printf_unlocked) -#define es_vfprintf _ESTREAM_PREFIX(es_vfprint) -#define es_vfprintf_unlocked _ESTREAM_PREFIX(es_vfprint_unlocked) -#define es_setvbuf _ESTREAM_PREFIX(es_setvbuf) -#define es_setbuf _ESTREAM_PREFIX(es_setbuf) -#define es_set_binary _ESTREAM_PREFIX(es_set_binary) -#define es_tmpfile _ESTREAM_PREFIX(es_tmpfile) -#define es_opaque_set _ESTREAM_PREFIX(es_opaque_set) -#define es_opaque_get _ESTREAM_PREFIX(es_opaque_get) -#define es_fname_set _ESTREAM_PREFIX(es_fname_set) -#define es_fname_get _ESTREAM_PREFIX(es_fname_get) -#define es_write_sanitized_utf8_buffer \ - _ESTREAM_PREFIX(es_write_sanitized_utf8_buffer) -#endif /*_ESTREAM_EXT_SYM_PREFIX*/ - - -#ifdef __cplusplus -extern "C" -{ -#if 0 -} -#endif -#endif - - -/* Forward declaration for the (opaque) internal type. */ -struct estream_internal; - -/* The definition of this struct is entirely private. You must not - use it for anything. It is only here so some functions can be - implemented as macros. */ -struct es__stream -{ - /* The layout of this struct must never change. It may be grown, - but only if all functions which access the new members are - versioned. */ - - /* A pointer to the stream buffer. */ - unsigned char *buffer; - - /* The size of the buffer in bytes. */ - size_t buffer_size; - - /* The length of the usable data in the buffer, only valid when in - read mode (see flags). */ - size_t data_len; - - /* The current position of the offset pointer, valid in read and - write mode. */ - size_t data_offset; - - size_t data_flushed; - unsigned char *unread_buffer; - size_t unread_buffer_size; - - /* The number of unread bytes. */ - size_t unread_data_len; - - /* Various flags. */ - struct { - unsigned int writing: 1; - unsigned int reserved: 7; - } flags; - - /* A pointer to our internal data for this stream. */ - struct estream_internal *intern; -}; - -/* The opaque type for an estream. */ -typedef struct es__stream *estream_t; - - -typedef ssize_t (*es_cookie_read_function_t) (void *cookie, - void *buffer, size_t size); -typedef ssize_t (*es_cookie_write_function_t) (void *cookie, - const void *buffer, - size_t size); -typedef int (*es_cookie_seek_function_t) (void *cookie, - off_t *pos, int whence); -typedef int (*es_cookie_close_function_t) (void *cookie); - -typedef struct es_cookie_io_functions -{ - es_cookie_read_function_t func_read; - es_cookie_write_function_t func_write; - es_cookie_seek_function_t func_seek; - es_cookie_close_function_t func_close; -} es_cookie_io_functions_t; - - -enum es_syshd_types - { - ES_SYSHD_NONE, /* No system handle available. */ - ES_SYSHD_FD, /* A file descriptor as returned by open(). */ - ES_SYSHD_SOCK, /* A socket as returned by socket(). */ - ES_SYSHD_RVID, /* A rendevous id (see libassuan's gpgcedev.c). */ - ES_SYSHD_HANDLE /* A HANDLE object (Windows). */ - }; - -typedef struct -{ - enum es_syshd_types type; - union { - int fd; - int sock; - int rvid; - void *handle; - } u; -} es_syshd_t; - - - - -#ifndef _ESTREAM_GCC_A_PRINTF -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) \ - __attribute__ ((format (__gnu_printf__,f,a))) -# elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) \ - __attribute__ ((format (printf,f,a))) -# else -# define _ESTREAM_GCC_A_PRINTF( f, a ) -# endif -#endif /*_ESTREAM_GCC_A_PRINTF*/ - - -#ifndef ES__RESTRICT -# if defined __GNUC__ && defined __GNUC_MINOR__ -# if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 92)) -# define ES__RESTRICT __restrict__ -# endif -# endif -#endif -#ifndef ES__RESTRICT -# define ES__RESTRICT -#endif - -int es_init (void); - -estream_t es_fopen (const char *ES__RESTRICT path, - const char *ES__RESTRICT mode); -estream_t es_mopen (void *ES__RESTRICT data, - size_t data_n, size_t data_len, - unsigned int grow, - void *(*func_realloc) (void *mem, size_t size), - void (*func_free) (void *mem), - const char *ES__RESTRICT mode); -estream_t es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode); -estream_t es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode, - const void *data, size_t datalen); -estream_t es_fdopen (int filedes, const char *mode); -estream_t es_fdopen_nc (int filedes, const char *mode); -estream_t es_sysopen (es_syshd_t *syshd, const char *mode); -estream_t es_sysopen_nc (es_syshd_t *syshd, const char *mode); -estream_t es_fpopen (FILE *fp, const char *mode); -estream_t es_fpopen_nc (FILE *fp, const char *mode); -estream_t es_freopen (const char *ES__RESTRICT path, - const char *ES__RESTRICT mode, - estream_t ES__RESTRICT stream); -estream_t es_fopencookie (void *ES__RESTRICT cookie, - const char *ES__RESTRICT mode, - es_cookie_io_functions_t functions); -int es_fclose (estream_t stream); -int es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen); -int es_onclose (estream_t stream, int mode, - void (*fnc) (estream_t, void*), void *fnc_value); -int es_fileno (estream_t stream); -int es_fileno_unlocked (estream_t stream); -int es_syshd (estream_t stream, es_syshd_t *syshd); -int es_syshd_unlocked (estream_t stream, es_syshd_t *syshd); - -void _es_set_std_fd (int no, int fd); -estream_t _es_get_std_stream (int fd); - -#define es_stdin _es_get_std_stream (0) -#define es_stdout _es_get_std_stream (1) -#define es_stderr _es_get_std_stream (2) - - -void es_flockfile (estream_t stream); -int es_ftrylockfile (estream_t stream); -void es_funlockfile (estream_t stream); - -int es_feof (estream_t stream); -int es_feof_unlocked (estream_t stream); -int es_ferror (estream_t stream); -int es_ferror_unlocked (estream_t stream); -void es_clearerr (estream_t stream); -void es_clearerr_unlocked (estream_t stream); - -int es_fflush (estream_t stream); -int es_fseek (estream_t stream, long int offset, int whence); -int es_fseeko (estream_t stream, off_t offset, int whence); -long int es_ftell (estream_t stream); -off_t es_ftello (estream_t stream); -void es_rewind (estream_t stream); - -int es_fgetc (estream_t stream); -int es_fputc (int c, estream_t stream); - -int _es_getc_underflow (estream_t stream); -int _es_putc_overflow (int c, estream_t stream); - -#define es_getc_unlocked(stream) \ - (((!(stream)->flags.writing) \ - && ((stream)->data_offset < (stream)->data_len) \ - && (! (stream)->unread_data_len)) \ - ? ((int) (stream)->buffer[((stream)->data_offset)++]) \ - : _es_getc_underflow ((stream))) - -#define es_putc_unlocked(c, stream) \ - (((stream)->flags.writing \ - && ((stream)->data_offset < (stream)->buffer_size) \ - && (c != '\n')) \ - ? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \ - : _es_putc_overflow ((c), (stream))) - -#define es_getc(stream) es_fgetc (stream) -#define es_putc(c, stream) es_fputc (c, stream) - -int es_ungetc (int c, estream_t stream); - -int es_read (estream_t ES__RESTRICT stream, - void *ES__RESTRICT buffer, size_t bytes_to_read, - size_t *ES__RESTRICT bytes_read); -int es_write (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, size_t bytes_to_write, - size_t *ES__RESTRICT bytes_written); -int es_write_sanitized (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, size_t length, - const char *delimiters, - size_t *ES__RESTRICT bytes_written); -int es_write_hexstring (estream_t ES__RESTRICT stream, - const void *ES__RESTRICT buffer, size_t length, - int reserved, size_t *ES__RESTRICT bytes_written); - -size_t es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems, - estream_t ES__RESTRICT stream); -size_t es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t memb, - estream_t ES__RESTRICT stream); - -char *es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream); -int es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream); -int es_fputs_unlocked (const char *ES__RESTRICT s, - estream_t ES__RESTRICT stream); - -ssize_t es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, - size_t *ES__RESTRICT n, - estream_t stream); -ssize_t es_read_line (estream_t stream, - char **addr_of_buffer, size_t *length_of_buffer, - size_t *max_length); -void es_free (void *a); - -int es_fprintf (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, ...) - _ESTREAM_GCC_A_PRINTF(2,3); -int es_fprintf_unlocked (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, ...) - _ESTREAM_GCC_A_PRINTF(2,3); - -int es_printf (const char *ES__RESTRICT format, ...) - _ESTREAM_GCC_A_PRINTF(1,2); -int es_printf_unlocked (const char *ES__RESTRICT format, ...) - _ESTREAM_GCC_A_PRINTF(1,2); - -int es_vfprintf (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, va_list ap) - _ESTREAM_GCC_A_PRINTF(2,0); -int es_vfprintf_unlocked (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT format, va_list ap) - _ESTREAM_GCC_A_PRINTF(2,0); - -char *es_asprintf (const char *ES__RESTRICT format, ...) - _ESTREAM_GCC_A_PRINTF(1,2); -char *es_vasprintf (const char *ES__RESTRICT format, va_list ap) - _ESTREAM_GCC_A_PRINTF(1,0); - -int es_setvbuf (estream_t ES__RESTRICT stream, - char *ES__RESTRICT buf, int mode, size_t size); -void es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf); - -void es_set_binary (estream_t stream); - - -estream_t es_tmpfile (void); - -void es_opaque_set (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque); -void *es_opaque_get (estream_t stream); - -void es_fname_set (estream_t stream, const char *fname); -const char *es_fname_get (estream_t stream); - - -#ifdef GNUPG_MAJOR_VERSION -int es_write_sanitized_utf8_buffer (estream_t stream, - const void *buffer, size_t length, - const char *delimiters, - size_t *bytes_written); -#endif /*GNUPG_MAJOR_VERSION*/ - -#ifdef __cplusplus -} -#endif -#endif /*ESTREAM_H*/ diff --git a/common/exechelp.h b/common/exechelp.h index 4d8e0fdd1..a9a9ca304 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -30,8 +30,6 @@ #ifndef GNUPG_COMMON_EXECHELP_H #define GNUPG_COMMON_EXECHELP_H -#include "../common/estream.h" - /* Return the maximum number of currently allowed file descriptors. Only useful on POSIX systems. */ diff --git a/common/http.c b/common/http.c index 06461dbb7..fe83e3fbc 100644 --- a/common/http.c +++ b/common/http.c @@ -1565,7 +1565,7 @@ send_request (http_t hd, const char *httphost, const char *auth, if (http_proxy && *http_proxy) { - request = es_asprintf + request = es_bsprintf ("%s %s://%s:%hu%s%s HTTP/1.0\r\n%s%s", hd->req_type == HTTP_REQ_GET ? "GET" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" : @@ -1585,7 +1585,7 @@ send_request (http_t hd, const char *httphost, const char *auth, else snprintf (portstr, sizeof portstr, ":%u", port); - request = es_asprintf + request = es_bsprintf ("%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s", hd->req_type == HTTP_REQ_GET ? "GET" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" : diff --git a/common/http.h b/common/http.h index 416e22065..3a4443034 100644 --- a/common/http.h +++ b/common/http.h @@ -31,7 +31,6 @@ #define GNUPG_COMMON_HTTP_H #include <gpg-error.h> -#include "../common/estream.h" struct uri_tuple_s { diff --git a/common/init.c b/common/init.c index 91ee912bb..1cbd709d7 100644 --- a/common/init.c +++ b/common/init.c @@ -173,7 +173,11 @@ _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp) #endif /* Initialize the Estream library. */ - es_init (); + gpgrt_init (); + gpgrt_set_alloc_func (gcry_realloc); +#ifdef USE_NPTH + gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); +#endif /* Special hack for Windows CE: We extract some options from arg to setup the standard handles. */ @@ -191,7 +195,7 @@ _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp) { int i; for (i=0; i < 3; i++) - (void)_es_get_std_stream (i); + (void)_gpgrt_get_std_stream (i); } /* --version et al shall use estream as well. */ diff --git a/common/iobuf.h b/common/iobuf.h index ef055477e..3889459e3 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -33,7 +33,6 @@ #include "../common/types.h" #include "../common/sysutils.h" -#include "../common/estream.h" #define DBG_IOBUF iobuf_debug_mode diff --git a/common/logging.h b/common/logging.h index 3b38f7370..7487b35d4 100644 --- a/common/logging.h +++ b/common/logging.h @@ -33,7 +33,6 @@ #define LIBJNLIB_LOGGING_H #include <stdio.h> -#include "estream.h" #include "mischelp.h" #include "w32help.h" diff --git a/common/membuf.c b/common/membuf.c index 6c9fee957..cc7772f29 100644 --- a/common/membuf.c +++ b/common/membuf.c @@ -132,7 +132,7 @@ put_membuf_printf (membuf_t *mb, const char *format, ...) char *buf; va_start (arg_ptr, format); - rc = estream_vasprintf (&buf, format, arg_ptr); + rc = gpgrt_vasprintf (&buf, format, arg_ptr); if (rc < 0) mb->out_of_core = errno ? errno : ENOMEM; va_end (arg_ptr); diff --git a/common/miscellaneous.c b/common/miscellaneous.c index 31c4e3811..862e952ea 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -145,6 +145,47 @@ print_fname_stdin (const char *s) } +static int +do_print_utf8_buffer (estream_t stream, + const void *buffer, size_t length, + const char *delimiters, size_t *bytes_written) +{ + const char *p = buffer; + size_t i; + + /* We can handle plain ascii simpler, so check for it first. */ + for (i=0; i < length; i++ ) + { + if ( (p[i] & 0x80) ) + break; + } + if (i < length) + { + int delim = delimiters? *delimiters : 0; + char *buf; + int ret; + + /*(utf8 conversion already does the control character quoting). */ + buf = utf8_to_native (p, length, delim); + if (bytes_written) + *bytes_written = strlen (buf); + ret = es_fputs (buf, stream); + xfree (buf); + return ret == EOF? ret : (int)i; + } + else + return es_write_sanitized (stream, p, length, delimiters, bytes_written); +} + + +void +print_utf8_buffer3 (estream_t stream, const void *p, size_t n, + const char *delim) +{ + do_print_utf8_buffer (stream, p, n, delim, NULL); +} + + void print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim) { @@ -152,14 +193,14 @@ print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim) tmp[0] = delim; tmp[1] = 0; - es_write_sanitized_utf8_buffer (stream, p, n, tmp, NULL); + do_print_utf8_buffer (stream, p, n, tmp, NULL); } void print_utf8_buffer (estream_t stream, const void *p, size_t n) { - es_write_sanitized_utf8_buffer (stream, p, n, NULL, NULL); + do_print_utf8_buffer (stream, p, n, NULL, NULL); } /* Write LENGTH bytes of BUFFER to FP as a hex encoded string. diff --git a/common/t-http.c b/common/t-http.c index 7b9c7446b..d4c974dc1 100644 --- a/common/t-http.c +++ b/common/t-http.c @@ -148,7 +148,7 @@ main (int argc, char **argv) const char *cafile = NULL; http_session_t session = NULL; - es_init (); + gpgrt_init (); log_set_prefix (PGM, 1 | 4); if (argc) { argc--; argv++; } diff --git a/common/ttyio.c b/common/ttyio.c index dee11cb8f..0f8c780c8 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -648,7 +648,7 @@ tty_getf (const char *promptfmt, ... ) char *answer; va_start (arg_ptr, promptfmt); - if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0) + if (gpgrt_vasprintf (&prompt, promptfmt, arg_ptr) < 0) log_fatal ("estream_vasprintf failed: %s\n", strerror (errno)); va_end (arg_ptr); answer = tty_get (prompt); diff --git a/common/util.h b/common/util.h index 4dad163c3..dd5fdb14c 100644 --- a/common/util.h +++ b/common/util.h @@ -33,16 +33,12 @@ #include <gcrypt.h> /* We need this for the memory function protos. */ #include <errno.h> /* We need errno. */ -#include <gpg-error.h> /* We need gpg_error_t. */ +#include <gpg-error.h> /* We need gpg_error_t and estream. */ /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) -/* Estream replaces most uses of stdio. */ -#include "../common/estream.h" -#include "../common/estream-printf.h" - /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/argparse.h" @@ -57,13 +53,13 @@ /* Redefine asprintf by our estream version which uses our own memory allocator.. */ -#define asprintf estream_asprintf -#define vasprintf estream_vasprintf +#define asprintf gpgrt_asprintf +#define vasprintf gpgrt_vasprintf /* Due to a bug in mingw32's snprintf related to the 'l' modifier and for increased portability we use our snprintf on all systems. */ #undef snprintf -#define snprintf estream_snprintf +#define snprintf gpgrt_snprintf /* GCC attributes. */ @@ -278,6 +274,8 @@ const char *gnupg_cipher_algo_name (int algo); const char *print_fname_stdout (const char *s); const char *print_fname_stdin (const char *s); +void print_utf8_buffer3 (estream_t fp, const void *p, size_t n, + const char *delim); void print_utf8_buffer2 (estream_t fp, const void *p, size_t n, int delim); void print_utf8_buffer (estream_t fp, const void *p, size_t n); void print_hexstring (FILE *fp, const void *buffer, size_t length, diff --git a/common/xasprintf.c b/common/xasprintf.c index b1fb9c692..8adf2e471 100644 --- a/common/xasprintf.c +++ b/common/xasprintf.c @@ -32,15 +32,14 @@ #include <errno.h> #include "util.h" -#include "iobuf.h" - -#if !defined(_ESTREAM_PRINTF_REALLOC) -#error Need to define _ESTREAM_PRINTF_REALLOC -#endif /* Same as asprintf but return an allocated buffer suitable to be freed using xfree. This function simply dies on memory failure, - thus no extra check is required. */ + thus no extra check is required. + + FIXME: We should remove these functions in favor of gpgrt_bsprintf + and a xgpgrt_bsprintf or rename them to xbsprintf and + xtrybsprintf. */ char * xasprintf (const char *fmt, ...) { @@ -48,7 +47,7 @@ xasprintf (const char *fmt, ...) char *buf; va_start (ap, fmt); - if (estream_vasprintf (&buf, fmt, ap) < 0) + if (gpgrt_vasprintf (&buf, fmt, ap) < 0) log_fatal ("estream_asprintf failed: %s\n", strerror (errno)); va_end (ap); return buf; @@ -63,7 +62,7 @@ xtryasprintf (const char *fmt, ...) char *buf; va_start (ap, fmt); - rc = estream_vasprintf (&buf, fmt, ap); + rc = gpgrt_vasprintf (&buf, fmt, ap); va_end (ap); if (rc < 0) return NULL; |