diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 58327c668..6ea266628 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -81,9 +81,16 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey, break; case GCRY_PK_ECC: - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(q%m)))", - curve, pkey[0]); + if (!curve) + err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve %s)(flags eddsa)(q%m)))", + "Ed25519", pkey[0]); + else + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve %s)(q%m)))", + curve, pkey[0]); break; default: @@ -139,6 +146,15 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + err = gcry_sexp_build (&s_skey, NULL, + "(private-key(ecc(curve%s)(flags eddsa)" + "(q%m)(d%m)))", + "Ed25519", skey[0], skey[1]); + } else err = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", @@ -198,11 +214,24 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, break; case GCRY_PK_ECC: - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(q%m)" - "(protected openpgp-native%S)))", - curve, skey[0], transfer_key); + if (!curve) + err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + err = gcry_sexp_build + (&s_skey, NULL, + "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)" + "(protected openpgp-native%S)))", + "Ed25519", skey[0], transfer_key); + } + else + err = gcry_sexp_build + (&s_skey, NULL, + "(protected-private-key(ecc(curve%s)(q%m)" + "(protected openpgp-native%S)))", + curve, skey[0], transfer_key); break; default: @@ -373,7 +402,7 @@ do_unprotect (const char *passphrase, if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1)) return gpg_error (GPG_ERR_BAD_SECKEY); - if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1)) + if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; const unsigned char *buffer; @@ -1064,15 +1093,36 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey, ndata = 20; /* Space for the SHA-1 checksum. */ for (i = npkey, j = 0; i < nskey; i++, j++ ) { - err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]); - if (err) + if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE)) { - err = gpg_error_from_syserror (); - for (i = 0; i < j; i++) - xfree (bufarr[i]); - return err; + const void *s; + unsigned int n; + + s = gcry_mpi_get_opaque (array[i], &n); + nbits[j] = n; + n = (n+7)/8; + narr[j] = n; + bufarr[j] = gcry_is_secure (s)? xtrymalloc_secure (n):xtrymalloc (n); + if (!bufarr[j]) + { + err = gpg_error_from_syserror (); + for (i = 0; i < j; i++) + xfree (bufarr[i]); + return err; + } + memcpy (bufarr[j], s, n); + } + else + { + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]); + if (err) + { + for (i = 0; i < j; i++) + xfree (bufarr[i]); + return err; + } + nbits[j] = gcry_mpi_get_nbits (array[i]); } - nbits[j] = gcry_mpi_get_nbits (array[i]); ndata += 2 + narr[j]; } @@ -1218,8 +1268,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, assert (iob.len < sizeof iobbuf -1); iobbuf[iob.len] = 0; err = gcry_sexp_build (&curve, NULL, "(curve %s)", iobbuf); - - gcry_log_debugsxp ("at 1", curve); } } else if (!strcmp (name, "ecdsa")) diff --git a/agent/protect.c b/agent/protect.c index 3a0021871..f633d562e 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -42,7 +42,9 @@ #include "cvt-openpgp.h" #include "sexp-parse.h" -#define PROT_CIPHER GCRY_CIPHER_AES +/* The protection mode for encryption. The supported modes for + decryption are listed in agent_unprotect(). */ +#define PROT_CIPHER GCRY_CIPHER_AES128 #define PROT_CIPHER_STRING "aes" #define PROT_CIPHER_KEYLEN (128/8) @@ -632,6 +634,7 @@ do_decryption (const unsigned char *protected, size_t protectedlen, const char *passphrase, const unsigned char *s2ksalt, unsigned long s2kcount, const unsigned char *iv, size_t ivlen, + int prot_cipher, int prot_cipher_keylen, unsigned char **result) { int rc = 0; @@ -640,11 +643,11 @@ do_decryption (const unsigned char *protected, size_t protectedlen, unsigned char *outbuf; size_t reallen; - blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER); + blklen = gcry_cipher_get_algo_blklen (prot_cipher); if (protectedlen < 4 || (protectedlen%blklen)) return gpg_error (GPG_ERR_CORRUPTED_PROTECTION); - rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC, + rc = gcry_cipher_open (&hd, prot_cipher, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE); if (rc) return rc; @@ -657,17 +660,16 @@ do_decryption (const unsigned char *protected, size_t protectedlen, if (!rc) { unsigned char *key; - size_t keylen = PROT_CIPHER_KEYLEN; - key = gcry_malloc_secure (keylen); + key = gcry_malloc_secure (prot_cipher_keylen); if (!key) rc = out_of_core (); else { rc = hash_passphrase (passphrase, GCRY_MD_SHA1, - 3, s2ksalt, s2kcount, key, keylen); + 3, s2ksalt, s2kcount, key, prot_cipher_keylen); if (!rc) - rc = gcry_cipher_setkey (hd, key, keylen); + rc = gcry_cipher_setkey (hd, key, prot_cipher_keylen); xfree (key); } } @@ -860,6 +862,15 @@ agent_unprotect (ctrl_t ctrl, gnupg_isotime_t protected_at, unsigned char **result, size_t *resultlen) { + static struct { + const char *name; /* Name of the protection method. */ + int algo; /* (A zero indicates the "openpgp-native" hack.) */ + int keylen; /* Used key length in bytes. */ + } algotable[] = { + { "openpgp-s2k3-sha1-aes-cbc", GCRY_CIPHER_AES128, (128/8)}, + { "openpgp-s2k3-sha1-aes256-cbc", GCRY_CIPHER_AES256, (256/8)}, + { "openpgp-native", 0, 0 } + }; int rc; const unsigned char *s; const unsigned char *protect_list; @@ -869,6 +880,7 @@ agent_unprotect (ctrl_t ctrl, const unsigned char *s2ksalt; unsigned long s2kcount; const unsigned char *iv; + int prot_cipher, prot_cipher_keylen; const unsigned char *prot_begin; unsigned char *cleartext; unsigned char *final; @@ -959,31 +971,40 @@ agent_unprotect (ctrl_t ctrl, n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); - if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc")) + + /* Lookup the protection algo. */ + prot_cipher = 0; /* (avoid gcc warning) */ + prot_cipher_keylen = 0; /* (avoid gcc warning) */ + for (i= 0; i < DIM (algotable); i++) + if (smatch (&s, n, algotable[i].name)) + { + prot_cipher = algotable[i].algo; + prot_cipher_keylen = algotable[i].keylen; + break; + } + if (i == DIM (algotable)) + return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION); + + if (!prot_cipher) /* This is "openpgp-native". */ { - if (smatch (&s, n, "openpgp-native")) + gcry_sexp_t s_prot_begin; + + rc = gcry_sexp_sscan (&s_prot_begin, NULL, + prot_begin, + gcry_sexp_canon_len (prot_begin, 0,NULL,NULL)); + if (rc) + return rc; + + rc = convert_from_openpgp_native (ctrl, s_prot_begin, passphrase, &final); + gcry_sexp_release (s_prot_begin); + if (!rc) { - gcry_sexp_t s_prot_begin; - - rc = gcry_sexp_sscan (&s_prot_begin, NULL, - prot_begin, - gcry_sexp_canon_len (prot_begin, 0,NULL,NULL)); - if (rc) - return rc; - - rc = convert_from_openpgp_native (ctrl, - s_prot_begin, passphrase, &final); - gcry_sexp_release (s_prot_begin); - if (!rc) - { - *result = final; - *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL); - } - return rc; + *result = final; + *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL); } - else - return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION); + return rc; } + if (*s != '(' || s[1] != '(') return gpg_error (GPG_ERR_INV_SEXP); s += 2; @@ -1026,7 +1047,7 @@ agent_unprotect (ctrl_t ctrl, s++; /* skip list end */ n = snext (&s); - if (n != 16) /* Wrong blocksize for IV (we support only aes-128). */ + if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */ return gpg_error (GPG_ERR_CORRUPTED_PROTECTION); iv = s; s += n; @@ -1040,7 +1061,7 @@ agent_unprotect (ctrl_t ctrl, cleartext = NULL; /* Avoid cc warning. */ rc = do_decryption (s, n, passphrase, s2ksalt, s2kcount, - iv, 16, + iv, 16, prot_cipher, prot_cipher_keylen, &cleartext); if (rc) return rc; diff --git a/build-aux/speedo.mk b/build-aux/speedo.mk index 69af39ce4..f81a835ee 100644 --- a/build-aux/speedo.mk +++ b/build-aux/speedo.mk @@ -376,8 +376,9 @@ speedo_pkg_glib_configure = \ CCC=$(host)-g++ \ LIBFFI_CFLAGS=-I$(idir)/lib/libffi-$(libffi_ver)/include \ LIBFFI_LIBS=\"-L$(idir)/lib -lffi\" +ifeq ($(TARGETOS),w32) speedo_pkg_glib_extracflags = -march=i486 - +endif speedo_pkg_libpng_configure = \ CPPFLAGS=\"-I$(idir)/include -DPNG_BUILD_DLL\" \ 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 -#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 . - * - * 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 -#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 -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T) -# ifdef HAVE_STDINT_H -# include -# endif -#endif -#ifdef HAVE_LANGINFO_THOUSANDS_SEP -#include -#endif -#ifdef HAVE_W32CE_SYSTEM -#include /* 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 . - * - * 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 -#include - -/* 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 . - * - * 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 -#endif - -#ifdef HAVE_CONFIG_H -# include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_W32_SYSTEM -# ifdef HAVE_WINSOCK2_H -# include -# endif -# include -#endif -#ifdef HAVE_W32CE_SYSTEM -# include /* 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 -#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 -#include - - - -#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= - - 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 . - * - * 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 -#include -#include - -/* 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 -#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 -#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/openpgp-oid.c b/common/openpgp-oid.c index bcb9885bc..010c23f60 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -37,6 +37,30 @@ #include "util.h" +/* A table with all our supported OpenPGP curves. */ +static struct { + const char *name; /* Standard name. */ + const char *oidstr; /* IETF formatted OID. */ + unsigned int nbits; /* Nominla bit length of the curve. */ + const char *alias; /* NULL or alternative name of the curve. */ +} oidtable[] = { + + { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519" }, + + { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, + { "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, + { "NIST P-521", "1.3.132.0.35", 521, "nistp521" }, + + { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 }, + { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 }, + { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 }, + + { "secp256k1", "1.3.132.0.10", 256 }, + + { NULL, NULL, 0} +}; + + /* The OID for Curve Ed25519 in OpenPGP format. */ static const char oid_ed25519[] = { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; @@ -270,56 +294,33 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a) const char * openpgp_curve_to_oid (const char *name, unsigned int *r_nbits) { + int i; unsigned int nbits = 0; - const char *oidstr; + const char *oidstr = NULL; - if (!name) - oidstr = NULL; - else if (!strcmp (name, "Ed25519") || !strcmp (name, "ed25519")) + if (name) { - oidstr = "1.3.6.1.4.1.11591.15.1"; - nbits = 255; + for (i=0; oidtable[i].name; i++) + if (!strcmp (oidtable[i].name, name) + || (oidtable[i].alias && !strcmp (oidtable[i].alias, name))) + { + oidstr = oidtable[i].oidstr; + nbits = oidtable[i].nbits; + break; + } + if (!oidtable[i].name) + { + /* If not found assume the input is already an OID and check + whether we support it. */ + for (i=0; oidtable[i].name; i++) + if (!strcmp (name, oidtable[i].oidstr)) + { + oidstr = oidtable[i].oidstr; + nbits = oidtable[i].nbits; + break; + } + } } - else if (!strcmp (name, "nistp256") || !strcmp (name, "NIST P-256")) - { - /* Libgcrypt uses "NIST P-256" as standard name for this curve - and thus the key generation returns this value. Thus we - allow both strings. */ - oidstr = "1.2.840.10045.3.1.7"; - nbits = 256; - } - else if (!strcmp (name, "nistp384") || !strcmp (name, "NIST P-384")) - { - oidstr = "1.3.132.0.34"; - nbits = 384; - } - else if (!strcmp (name, "nistp521") || !strcmp (name, "NIST P-521")) - { - oidstr = "1.3.132.0.35"; - nbits = 521; - } - else if (!strcmp (name,"brainpoolP256r1")) - { - oidstr = "1.3.36.3.3.2.8.1.1.7"; - nbits = 256; - } - else if (!strcmp (name, "brainpoolP384r1")) - { - oidstr = "1.3.36.3.3.2.8.1.1.11"; - nbits = 384; - } - else if (!strcmp (name, "brainpoolP512r1")) - { - oidstr = "1.3.36.3.3.2.8.1.1.13"; - nbits = 512; - } - else if (!strcmp (name, "secp256k1")) - { - oidstr = "1.3.132.0.10"; - nbits = 256; - } - else - oidstr = NULL; if (r_nbits) *r_nbits = nbits; @@ -328,32 +329,19 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits) /* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns "?" for - unknown curve names. */ + unknown curve names. We prefer an alias name here which is more + suitable for printing. */ const char * -openpgp_oid_to_curve (const char *oid) +openpgp_oid_to_curve (const char *oidstr) { - const char *name; + int i; - if (!oid) - name = ""; - else if (!strcmp (oid, "1.3.6.1.4.1.11591.15.1")) - name = "ed25519"; - else if (!strcmp (oid, "1.2.840.10045.3.1.7")) - name = "nistp256"; - else if (!strcmp (oid, "1.3.132.0.10")) - name = "secp256k1"; - else if (!strcmp (oid, "1.3.132.0.34")) - name = "nistp384"; - else if (!strcmp (oid, "1.3.132.0.35")) - name = "nistp521"; - else if (!strcmp (oid, "1.3.36.3.3.2.8.1.1.7")) - name = "brainpoolP256r1"; - else if (!strcmp (oid, "1.3.36.3.3.2.8.1.1.11")) - name = "brainpoolP384r1"; - else if (!strcmp (oid, "1.3.36.3.3.2.8.1.1.13")) - name = "brainpoolP512r1"; - else - name = "?"; + if (!oidstr) + return ""; - return name; + for (i=0; oidtable[i].name; i++) + if (!strcmp (oidtable[i].oidstr, oidstr)) + return oidtable[i].alias? oidtable[i].alias : oidtable[i].name; + + return "?"; } 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 /* We need this for the memory function protos. */ #include /* We need errno. */ -#include /* We need gpg_error_t. */ +#include /* 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 #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; diff --git a/configure.ac b/configure.ac index ec259c322..80af6face 100644 --- a/configure.ac +++ b/configure.ac @@ -50,7 +50,7 @@ m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist)) m4_esyscmd([echo ]mym4_version[>VERSION]) AC_INIT([mym4_package],[mym4_version], [http://bugs.gnupg.org]) -NEED_GPG_ERROR_VERSION=1.13 +NEED_GPG_ERROR_VERSION=1.14 NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_VERSION=1.6.0 @@ -497,6 +497,8 @@ AH_BOTTOM([ # endif #endif +/* Provide the es_ macro for estream. */ +#define GPGRT_ENABLE_ES_MACROS 1 /* Tell libgcrypt not to use its own libgpg-error implementation. */ #define USE_LIBGPG_ERROR 1 @@ -515,11 +517,6 @@ AH_BOTTOM([ handler. */ #define HTTP_NO_WSASTARTUP -/* We want to use the libgcrypt provided memory allocation for - asprintf. */ -#define _ESTREAM_PRINTF_REALLOC gcry_realloc -#define _ESTREAM_PRINTF_EXTRA_INCLUDE "../common/util.h" - /* Under Windows we use the gettext code from libgpg-error. */ #define GPG_ERR_ENABLE_GETTEXT_MACROS @@ -1495,14 +1492,6 @@ if test "$GCC" = yes; then if test x"$_gcc_psign" = xyes ; then CFLAGS="$CFLAGS -Wpointer-arith" fi - - # The undocumented option -Wno-psabi suppresses the annoying - # "the ABI of passing union with long double has changed in GCC 4.4" - # which is emitted in estream-printf.c but entirely irrelvant - # because that union is local to the file. - if test x"$_gcc_silent_wno" = xyes ; then - CFLAGS="$CFLAGS -Wno-psabi" - fi fi @@ -1517,12 +1506,6 @@ AC_ARG_ENABLE(optimization, CFLAGS=`echo $CFLAGS | sed s/-O[[1-9]]\ /-O0\ /g` fi]) -# -# Prepare building of estream -# -estream_INIT - - # # Decide what to build # diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 8505f9c40..d10e3ca78 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -113,7 +113,6 @@ #include "crlfetch.h" #include "misc.h" #include "cdb.h" -#include "estream-printf.h" /* Change this whenever the format changes */ #define DBDIR_D (opt.system_daemon? "crls.d" : "dirmngr-cache.d") @@ -818,8 +817,8 @@ update_dir (crl_cache_t cache) nodename = utsbuf.nodename; #endif - estream_asprintf (&tmpbuf, "DIR-tmp-%s-%u-%p.txt.tmp", - nodename, (unsigned int)getpid (), &tmpbuf); + gpgrt_asprintf (&tmpbuf, "DIR-tmp-%s-%u-%p.txt.tmp", + nodename, (unsigned int)getpid (), &tmpbuf); if (!tmpbuf) { err = gpg_error_from_errno (errno); @@ -2022,8 +2021,8 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) nodename = utsbuf.nodename; #endif - estream_asprintf (&tmpfname, "crl-tmp-%s-%u-%p.db.tmp", - nodename, (unsigned int)getpid (), &tmpfname); + gpgrt_asprintf (&tmpfname, "crl-tmp-%s-%u-%p.db.tmp", + nodename, (unsigned int)getpid (), &tmpfname); if (!tmpfname) { err = gpg_error_from_syserror (); diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index c682d1856..f335de8c7 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -29,7 +29,6 @@ #include "misc.h" #include "http.h" -#include "estream.h" #include "ldap-wrapper.h" diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c index 7d3bd1794..daa2d1bcb 100644 --- a/dirmngr/dirmngr_ldap.c +++ b/dirmngr/dirmngr_ldap.c @@ -50,6 +50,7 @@ #define JNLIB_NEED_LOG_LOGV +#include #include "../common/logging.h" #include "../common/argparse.h" #include "../common/stringhelp.h" diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index 495f7fa93..e4cd8f165 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -67,7 +67,7 @@ ks_printf_help (ctrl_t ctrl, const char *format, ...) char *buf; va_start (arg_ptr, format); - buf = es_vasprintf (format, arg_ptr); + buf = es_vbsprintf (format, arg_ptr); err = buf? 0 : gpg_error_from_syserror (); va_end (arg_ptr); if (!err) diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index a2faa751a..dc950cf3c 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -20,13 +20,12 @@ #ifndef DIRMNGR_KS_ENGINE_H #define DIRMNGR_KS_ENGINE_H 1 -#include "../common/estream.h" #include "../common/http.h" /*-- ks-action.c --*/ gpg_error_t ks_print_help (ctrl_t ctrl, const char *text); gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format, - ...) _ESTREAM_GCC_A_PRINTF(2,3); + ...) JNLIB_GCC_A_PRINTF(2,3); /*-- ks-engine-hkp.c --*/ gpg_error_t ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri); diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index 0d506efcd..f8c437d1d 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -30,7 +30,6 @@ #include "validate.h" #include "certcache.h" #include "ocsp.h" -#include "estream.h" /* The maximum size we allow as a response from an OCSP reponder. */ #define MAX_RESPONSE_SIZE 65536 diff --git a/doc/gpg.texi b/doc/gpg.texi index 7ac1613f9..e9bcff3ec 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3509,7 +3509,7 @@ sense. Although OpenPGP works with time intervals, GnuPG uses an absolute value internally and thus the last year we can represent is 2105. -@item Ceation-Date: @var{iso-date} +@item Creation-Date: @var{iso-date} Set the creation date of the key as stored in the key information and which is also part of the fingerprint calculation. Either a date like "1986-04-26" or a full timestamp like "19860426T042640" may be used. diff --git a/doc/instguide.texi b/doc/instguide.texi index d6815e209..aff39556c 100644 --- a/doc/instguide.texi +++ b/doc/instguide.texi @@ -13,7 +13,7 @@ include brief information on how to set up the whole thing. Please watch the GnuPG website for updates of the documentation. In the meantime you may search the GnuPG mailing list archives or ask on the gnupg-users mailing listsfor advise on how to solve problems or how to -get that whole thing up and running. +get that whole thing up and running. ** Building the software @@ -22,7 +22,7 @@ that you are already reading this documentation we can only give some extra hints To comply with the rules on GNU systems you should have build time -configured @command{dirmngr} using: +configured @command{gnupg} using: @example ./configure --sysconfdir=/etc --localstatedir=/var @@ -36,19 +36,7 @@ the binaries get installed. If you selected to use the the default then. - -** Explain how to setup a root CA key as trusted - - -Such questions may also help to write a proper installation guide. - -[to be written] - - -XXX Tell how to setup the system, install certificates, how dirmngr relates -to GnuPG etc. - -** Explain how to setup a root CA key as trusted +** Notes on setting a root CA key to trusted X.509 is based on a hierarchical key infrastructure. At the root of the tree a trusted anchor (root certificate) is required. There are usually @@ -64,28 +52,26 @@ contains a few root certificates. Most installations will need more. @item Let @command{gpgsm} ask you whether you want to insert a new root -certificate. To enable this feature you need to set the option -@option{allow-mark-trusted} into @file{gpg-agent.conf}. In general it -is not a good idea to do it this way. Checking whether a root -certificate is really trustworthy requires decisions, which casual -users are not up to. Thus, by default this option is not enabled. +certificate. This feature is enabled by default; you may disable it +using the option @option{no-allow-mark-trusted} into +@file{gpg-agent.conf}. -@item +@item Manually maintain the list of trusted root certificates. For a multi user installation this can be done once for all users on a machine. -Specific changes on a per-user base are also possible. +Specific changes on a per-user base are also possible. @end itemize -XXX decribe how to maintain trustlist.txt and /etc/gnupg/trustlist.txt. +@c decribe how to maintain trustlist.txt and /etc/gnupg/trustlist.txt. -** How to get the ssh support running - -XXX How to use the ssh support. +@c ** How to get the ssh support running +@c +@c XXX How to use the ssh support. -@section Installation Overview - -XXXX +@c @section Installation Overview +@c +@c XXXX diff --git a/g10/export.c b/g10/export.c index 6a921c192..b4f1a2e4d 100644 --- a/g10/export.c +++ b/g10/export.c @@ -462,7 +462,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) xfree (string); string = NULL; if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) || gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) - || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY) + || !npkey || npkey >= nskey) goto bad_seckey; /* Check that the pubkey algo matches the one from the public key. */ @@ -503,6 +503,10 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) goto leave; } + /* This check has to go after the ecc adjustments. */ + if (nskey > PUBKEY_MAX_NSKEY) + goto bad_seckey; + /* Parse the key parameters. */ gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "skey", 0); diff --git a/g10/keygen.c b/g10/keygen.c index 1bf534837..c2c31d52e 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -338,23 +338,14 @@ keygen_set_std_prefs (const char *string,int personal) strcat(dummy_string,"S8 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) ) strcat(dummy_string,"S7 "); - if ( !openpgp_cipher_test_algo (CIPHER_ALGO_CAST5) ) - strcat(dummy_string,"S3 "); strcat(dummy_string,"S2 "); /* 3DES */ /* The default hash algo order is: - SHA-256, SHA-1, SHA-384, SHA-512, SHA-224. - Ordering SHA-1 before SHA-384 might be viewed as a bit - strange; it is done because we expect that soon enough - SHA-3 will be available and at that point there should - be no more need for SHA-384 etc. Anyway this order is - just a default and can easily be changed by a config - option. */ + SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. + */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); - strcat (dummy_string, "H2 "); /* SHA-1 */ - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); @@ -364,6 +355,8 @@ keygen_set_std_prefs (const char *string,int personal) if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); + strcat (dummy_string, "H2 "); /* SHA-1 */ + if(!check_compress_algo(COMPRESS_ALGO_ZLIB)) { strcat(dummy_string,"Z2 "); diff --git a/g10/pkglue.c b/g10/pkglue.c index 67d2efd39..684ce8a1d 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -190,7 +190,9 @@ int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, PKT_public_key *pk, gcry_mpi_t *pkey) { - gcry_sexp_t s_ciph, s_data, s_pkey; + gcry_sexp_t s_ciph = NULL; + gcry_sexp_t s_data = NULL; + gcry_sexp_t s_pkey = NULL; int rc; /* Make a sexp from pkey. */ @@ -200,9 +202,8 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); /* Put DATA into a simplified S-expression. */ - if (rc || gcry_sexp_build (&s_data, NULL, "%m", data)) - BUG (); - + if (!rc) + rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E) { @@ -210,40 +211,42 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); /* Put DATA into a simplified S-expression. */ - if (rc || gcry_sexp_build (&s_data, NULL, "%m", data)) - BUG (); + if (!rc) + rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t k; - char *curve; rc = pk_ecdh_generate_ephemeral_key (pkey, &k); - if (rc) - return rc; - - curve = openpgp_oid_to_str (pkey[0]); - if (!curve) - rc = gpg_error_from_syserror (); - else + if (!rc) { - /* Now use the ephemeral secret to compute the shared point. */ - rc = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecdh(curve%s)(q%m)))", - curve, pkey[1]); - xfree (curve); - /* FIXME: Take care of RC. */ - /* Put K into a simplified S-expression. */ - if (rc || gcry_sexp_build (&s_data, NULL, "%m", k)) - BUG (); + char *curve; + + curve = openpgp_oid_to_str (pkey[0]); + if (!curve) + rc = gpg_error_from_syserror (); + else + { + /* Now use the ephemeral secret to compute the shared point. */ + rc = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecdh(curve%s)(q%m)))", + curve, pkey[1]); + xfree (curve); + /* Put K into a simplified S-expression. */ + if (!rc) + rc = gcry_sexp_build (&s_data, NULL, "%m", k); + } + gcry_mpi_release (k); } } else - return gpg_error (GPG_ERR_PUBKEY_ALGO); - + rc = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Pass it to libgcrypt. */ - rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); + if (!rc) + rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); + gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); diff --git a/g13/create.c b/g13/create.c index 315ff1337..58ab5904f 100644 --- a/g13/create.c +++ b/g13/create.c @@ -34,7 +34,6 @@ #include "backend.h" #include "utils.h" #include "call-gpg.h" -#include "estream.h" /* Create a new blob with all the session keys and other meta information which are to be stored encrypted in the crypto diff --git a/g13/g13.h b/g13/g13.h index 8e6867a23..bdcc02ae5 100644 --- a/g13/g13.h +++ b/g13/g13.h @@ -28,7 +28,6 @@ #include "../common/util.h" #include "../common/status.h" -#include "../common/estream.h" #include "../common/session-env.h" /* A large struct named "opt" to keep global flags. */ diff --git a/g13/mount.c b/g13/mount.c index ab9f2f340..512e29d1a 100644 --- a/g13/mount.c +++ b/g13/mount.c @@ -34,7 +34,6 @@ #include "backend.h" #include "utils.h" #include "call-gpg.h" -#include "estream.h" #include "mountinfo.h" #include "runner.h" diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c index b0225e9da..34cbc5394 100644 --- a/kbx/kbxutil.c +++ b/kbx/kbxutil.c @@ -29,6 +29,7 @@ #include #define JNLIB_NEED_LOG_LOGV +#include #include "../common/logging.h" #include "../common/argparse.h" #include "../common/stringhelp.h" diff --git a/m4/Makefile.am b/m4/Makefile.am index f94c0c1b2..05a2be366 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -8,8 +8,6 @@ EXTRA_DIST += gpg-error.m4 libgcrypt.m4 libassuan.m4 ksba.m4 EXTRA_DIST += autobuild.m4 -EXTRA_DIST += estream.m4 - EXTRA_DIST += sys_socket_h.m4 socklen.m4 EXTRA_DIST += ChangeLog-2011 diff --git a/m4/estream.m4 b/m4/estream.m4 deleted file mode 100644 index b61059a47..000000000 --- a/m4/estream.m4 +++ /dev/null @@ -1,49 +0,0 @@ -dnl Autoconf macros for libestream -dnl Copyright (C) 2007 g10 Code GmbH -dnl -dnl This file is free software; as a special exception the author gives -dnl unlimited permission to copy and/or distribute it, with or without -dnl modifications, as long as this notice is preserved. -dnl -dnl This file is distributed in the hope that it will be useful, but -dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - -dnl estream_PRINTF_INIT -dnl Prepare build of source included estream-printf.c -dnl -AC_DEFUN([estream_PRINTF_INIT], -[ - AC_MSG_NOTICE([checking system features for estream-printf]) - AC_CHECK_HEADERS(stdint.h) - AC_TYPE_LONG_LONG_INT - AC_TYPE_LONG_DOUBLE - AC_TYPE_INTMAX_T - AC_TYPE_UINTMAX_T - AC_CHECK_TYPES([ptrdiff_t]) - AC_CHECK_SIZEOF([unsigned long]) - AC_CHECK_SIZEOF([void *]) - AC_CACHE_CHECK([for nl_langinfo and THOUSANDS_SEP], - estream_cv_langinfo_thousands_sep, - [AC_TRY_LINK([#include ], - [char* cs = nl_langinfo(THOUSANDS_SEP); return !cs;], - estream_cv_langinfo_thousands_sep=yes, - estream_cv_langinfo_thousands_sep=no) - ]) - if test $estream_cv_langinfo_thousands_sep = yes; then - AC_DEFINE(HAVE_LANGINFO_THOUSANDS_SEP, 1, - [Define if you have and nl_langinfo(THOUSANDS_SEP).]) - fi -]) - - -dnl estream_INIT -dnl Prepare build of source included estream.c -dnl -AC_DEFUN([estream_INIT], -[ - AC_REQUIRE([estream_PRINTF_INIT]) - AC_MSG_NOTICE([checking system features for estream]) - -]) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index fff097adb..9b4ab2220 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1448,9 +1448,8 @@ get_public_key (app_t app, int keyno) } hexkeyid = fpr + 24; - ret = estream_asprintf (&command, - "gpg --list-keys --with-colons --with-key-data '%s'", - fpr); + ret = gpgrt_asprintf + (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr); if (ret < 0) { err = gpg_error_from_syserror (); diff --git a/scd/atr.c b/scd/atr.c index c3fa49f4b..5b94758a5 100644 --- a/scd/atr.c +++ b/scd/atr.c @@ -24,7 +24,7 @@ #include #include -#include "../common/estream.h" +#include #include "../common/logging.h" #include "atr.h" diff --git a/scd/command.c b/scd/command.c index 05b50b935..dd4191f44 100644 --- a/scd/command.c +++ b/scd/command.c @@ -686,8 +686,8 @@ cmd_learn (assuan_context_t ctx, char *line) { char *command; - rc = estream_asprintf (&command, "KNOWNCARDP %s %lu", - serial, (unsigned long)stamp); + rc = gpgrt_asprintf (&command, "KNOWNCARDP %s %lu", + serial, (unsigned long)stamp); if (rc < 0) { xfree (serial); @@ -915,7 +915,7 @@ pin_cb (void *opaque, const char *info, char **retstr) if (info) { log_debug ("prompting for pinpad entry '%s'\n", info); - rc = estream_asprintf (&command, "POPUPPINPADPROMPT %s", info); + rc = gpgrt_asprintf (&command, "POPUPPINPADPROMPT %s", info); if (rc < 0) return gpg_error (gpg_err_code_from_errno (errno)); rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); @@ -935,7 +935,7 @@ pin_cb (void *opaque, const char *info, char **retstr) *retstr = NULL; log_debug ("asking for PIN '%s'\n", info); - rc = estream_asprintf (&command, "NEEDPIN %s", info); + rc = gpgrt_asprintf (&command, "NEEDPIN %s", info); if (rc < 0) return gpg_error (gpg_err_code_from_errno (errno)); @@ -2340,7 +2340,7 @@ update_reader_status_file (int set_card_removed_flag) gpg_error_t err; homestr = make_filename (opt.homedir, NULL); - if (estream_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0) + if (gpgrt_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0) log_error ("out of core while building environment\n"); else { diff --git a/scd/scdaemon.c b/scd/scdaemon.c index aa1588392..9cc4d117c 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -826,8 +826,8 @@ main (int argc, char **argv ) close (fd); /* create the info string: :: */ - if (estream_asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1", - socket_name, (ulong) pid) < 0) + if (gpgrt_asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1", + socket_name, (ulong) pid) < 0) { log_error ("out of core\n"); kill (pid, SIGTERM); diff --git a/sm/certdump.c b/sm/certdump.c index 21a5e292c..23cca7385 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -504,9 +504,8 @@ print_dn_part (FILE *fp, estream_t stream, { es_fprintf (stream, "/%s=", dn->key); if (translate) - es_write_sanitized_utf8_buffer (stream, dn->value, - strlen (dn->value), - "/", NULL); + print_utf8_buffer3 (stream, dn->value, strlen (dn->value), + "/"); else es_write_sanitized (stream, dn->value, strlen (dn->value), "/", NULL); @@ -716,8 +715,7 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate) if (s2) { if (translate) - es_write_sanitized_utf8_buffer (fp, s + 1, s2 - (char*)s - 1, - NULL, NULL); + print_utf8_buffer (fp, s + 1, s2 - (char*)s - 1); else es_write_sanitized (fp, s + 1, s2 - (char*)s - 1, NULL, NULL); }