Page MenuHome GnuPG

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/NEWS b/NEWS
index 35532e5..6099d5b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,482 +1,483 @@
Noteworthy changes in version 1.14 (unreleased)
-----------------------------------------------
* Added trylock function
* Added the estream library under the name gpgrt and a set of macros
to use them with their "es_" names.
* Interface changes relative to the 1.13 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_KEY_DISABLED NEW.
gpgrt_init NEW macro.
gpgrt_check_version NEW.
gpgrt_lock_trylock NEW.
gpgrt_set_syscall_clamp NEW.
+ gpgrt_set_alloc_func NEW.
gpgrt_stream_t NEW.
gpgrt_cookie_io_functions_t NEW.
gpgrt_syshd_t NEW.
GPGRT_SYSHD_NONE NEW.
GPGRT_SYSHD_FD NEW.
GPGRT_SYSHD_SOCK NEW.
GPGRT_SYSHD_RVID NEW.
GPGRT_SYSHD_HANDLE NEW.
gpgrt_stdin NEW macro.
gpgrt_stdout NEW macro.
gpgrt_stderr NEW macro.
gpgrt_fopen NEW.
gpgrt_mopen NEW.
gpgrt_fopenmem NEW.
gpgrt_fopenmem_init NEW.
gpgrt_fdopen NEW.
gpgrt_fdopen_nc NEW.
gpgrt_sysopen NEW.
gpgrt_sysopen_nc NEW.
gpgrt_fpopen NEW.
gpgrt_fpopen_nc NEW.
gpgrt_freopen NEW.
gpgrt_fopencookie NEW.
gpgrt_fclose NEW.
gpgrt_fclose_snatch NEW.
gpgrt_onclose NEW.
gpgrt_fileno NEW.
gpgrt_fileno_unlocked NEW.
gpgrt_syshd NEW.
gpgrt_syshd_unlocked NEW.
gpgrt_flockfile NEW.
gpgrt_ftrylockfile NEW.
gpgrt_funlockfile NEW.
gpgrt_feof NEW.
gpgrt_feof_unlocked NEW.
gpgrt_ferror NEW.
gpgrt_ferror_unlocked NEW.
gpgrt_clearerr NEW.
gpgrt_clearerr_unlocked NEW.
gpgrt_fflush NEW.
gpgrt_fseek NEW.
gpgrt_fseeko NEW.
gpgrt_ftell NEW.
gpgrt_ftello NEW.
gpgrt_rewind NEW.
gpgrt_getc NEW macro.
gpgrt_getc_unlocked NEW macro.
gpgrt_fgetc NEW.
gpgrt_fputc NEW.
gpgrt_ungetc NEW.
gpgrt_read NEW.
gpgrt_write NEW.
gpgrt_write_sanitized NEW.
gpgrt_write_hexstring NEW.
gpgrt_fread NEW.
gpgrt_fwrite NEW.
gpgrt_fgets NEW.
gpgrt_putc NEW macro.
gpgrt_putc_unlocked NEW macro.
gpgrt_fputs NEW.
gpgrt_fputs_unlocked NEW.
gpgrt_getline NEW.
gpgrt_read_line NEW.
gpgrt_free NEW.
gpgrt_fprintf NEW.
gpgrt_fprintf_unlocked NEW.
gpgrt_printf NEW.
gpgrt_printf_unlocked NEW.
gpgrt_vfprintf NEW.
gpgrt_vfprintf_unlocked NEW.
gpgrt_setvbuf NEW.
gpgrt_setbuf NEW.
gpgrt_set_binary NEW.
gpgrt_tmpfile NEW.
gpgrt_opaque_set NEW.
gpgrt_opaque_get NEW.
gpgrt_fname_set NEW.
gpgrt_fname_get NEW.
gpgrt_asprintf NEW.
gpgrt_vasprintf NEW.
gpgrt_bsprintf NEW.
gpgrt_vbsprintf NEW.
gpgrt_snprintf NEW.
gpgrt_vsnprintf NEW.
Noteworthy changes in version 1.13 (2014-04-15) [C11/A11/R0]
-----------------------------------------------
* Added a portable mutex API.
* The AM_PATH_GPG_ERROR macro now defines GPG_ERROR_MT_CFLAGS and
GPG_ERROR_MT_LIBS autoconf output variables for use by programs
which need gpgrt based thread support. gpg-error-config has a new
option --mt.
* Interface changes relative to the 1.12 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_KEY_ON_CARD NEW.
GPG_ERR_MAC_ALGO NEW.
GPG_ERR_INV_LOCK_OBJ NEW.
gpgrt_lock_t NEW.
GPGRT_LOCK_INITIALIZER NEW.
GPGRT_LOCK_DEFINE NEW.
gpgrt_lock_init NEW.
gpgrt_lock_lock NEW.
gpgrt_lock_unlock NEW.
gpgrt_lock_destroy NEW.
gpgrt_yield NEW.
Noteworthy changes in version 1.12 (2013-06-24)
-----------------------------------------------
* Add support for 64 bit Windows (use ./autogen.sh --build-w64).
* Fixed parsing and installing of the Windows .def file.
* Interface changes relative to the 1.11 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_NO_CRYPT_CTX NEW.
GPG_ERR_WRONG_CRYPT_CTX NEW.
GPG_ERR_BAD_CRYPT_CTX NEW.
GPG_ERR_CRYPT_CTX_CONFLICT NEW.
GPG_ERR_BROKEN_PUBKEY NEW.
GPG_ERR_BROKEN_SECKEY NEW.
Noteworthy changes in version 1.11 (2013-02-25)
-----------------------------------------------
* New error source GPG_ERR_SOURCE_ASSUAN for Libassuan related
errors.
* New macros GPG_ERROR_VERSION and GPG_ERROR_VERSION_NUMBER. New
function gpg_error_check_version.
* Interface changes relative to the 1.10 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_NO_KEYSERVER NEW.
GPG_ERR_INV_CURVE NEW.
GPG_ERR_UNKNOWN_CURVE NEW.
GPG_ERR_DUP_KEY NEW.
GPG_ERR_AMBIGUOUS NEW.
GPG_ERR_SOURCE_ASSUAN NEW.
gpg_error_check_version NEW.
GPG_ERROR_VERSION NEW.
GPG_ERROR_VERSION_NUMBER NEW.
Noteworthy changes in version 1.10 (2010-10-26)
-----------------------------------------------
* Using a static library on W32 does now work.
* Interface changes relative to the 1.9 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_NOT_INITIALIZED NEW.
GPG_ERR_MISSING_ISSUER_CERT NEW.
GPG_ERR_FULLY_CANCELED NEW.
Noteworthy changes in version 1.9 (2010-07-21)
----------------------------------------------
* New function gpg_err_deinit.
* Fix building of static lib under W32.
* Interface changes relative to the 1.8 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_MISSING_KEY NEW.
GPG_ERR_TOO_MANY NEW.
GPG_ERR_LIMIT_REACHED NEW.
gpg_err_deinit NEW.
Noteworthy changes in version 1.8 (2010-05-06)
----------------------------------------------
* Support for WindowsCE.
* New option --list for gpg-error.
* Interface changes relative to the 1.7 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_NOT_ENABLED NEW.
GPG_ERR_SOURCE_G13 NEW.
GPG_ERR_NO_ENGINE NEW.
gpg_err_set_errno NEW.
Noteworthy changes in version 1.7 (2008-11-26)
----------------------------------------------
* Minor fixes and a few new error codes.
* Interface changes relative to the 1.6 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_NOT_OPERATIONAL NEW
GPG_ERR_NO_PASSPHRASE NEW
GPG_ERR_NO_PIN NEW
Noteworthy changes in version 1.6 (2007-10-29)
----------------------------------------------
* Fixed a build problem under Windows.
* Interface changes relative to the 1.4 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_UNFINISHED NEW
GPG_ERR_SOURCE_GPA NEW
GPG_ERR_SOURCE_KLEO NEW
Noteworthy changes in version 1.5 (2006-11-30)
----------------------------------------------
* Minor build system fixes.
* Updated gettext. Removed included gettext copy.
* gpg-error has a new option --version.
Noteworthy changes in version 1.4 (2006-09-14)
----------------------------------------------
* Support for Common Lisp is included.
* New error codes for the Assuan IPC library.
* New error code GPG_ERR_MISSING_ERRNO to be used in cases when a
system accidently does not set errno but a system error definitely
occured.
* New error source GPG_ERR_SOURCE_ANY to allow proper use of
libgpg-error even if a specific source is not available.
* New convenience functions gpg_err_code_from_syserror and
gpg_error_from_syserror which make sure never to return 0.
* Interface changes relative to the 1.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpg_err_code_from_syserror NEW
gpg_error_from_syserror NEW
GPG_ERR_SOURCE_ANY NEW
GPG_ERR_MISSING_ERRNO NEW
GPG_ERR_UNKNOWN_OPTION NEW
GPG_ERR_UNKNOWN_COMMAND NEW
GPG_ERR_ASS_GENERAL NEW
GPG_ERR_ASS_ACCEPT_FAILED NEW
GPG_ERR_ASS_CONNECT_FAILED NEW
GPG_ERR_ASS_INV_RESPONSE NEW
GPG_ERR_ASS_INV_VALUE NEW
GPG_ERR_ASS_INCOMPLETE_LINE NEW
GPG_ERR_ASS_LINE_TOO_LONG NEW
GPG_ERR_ASS_NESTED_COMMANDS NEW
GPG_ERR_ASS_NO_DATA_CB NEW
GPG_ERR_ASS_NO_INQUIRE_CB NEW
GPG_ERR_ASS_NOT_A_SERVER NEW
GPG_ERR_ASS_NOT_A_CLIENT NEW
GPG_ERR_ASS_SERVER_START NEW
GPG_ERR_ASS_READ_ERROR NEW
GPG_ERR_ASS_WRITE_ERROR NEW
GPG_ERR_ASS_TOO_MUCH_DATA NEW
GPG_ERR_ASS_UNEXPECTED_CMD NEW
GPG_ERR_ASS_UNKNOWN_CMD NEW
GPG_ERR_ASS_SYNTAX NEW
GPG_ERR_ASS_CANCELED NEW
GPG_ERR_ASS_NO_INPUT NEW
GPG_ERR_ASS_NO_OUTPUT NEW
GPG_ERR_ASS_PARAMETER NEW
GPG_ERR_ASS_UNKNOWN_INQUIRE NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 1.3 (2006-03-14)
----------------------------------------------
* GNU gettext is included for systems that do not provide it.
Noteworthy changes in version 1.2 (2006-03-03)
----------------------------------------------
* New function gpg_err_init, which binds the locale directory to
the text domain. This function is a constructor on GCC targets,
so it does not need to be called explicitely. The header file
defines GPG_ERR_INITIALIZED in this case. This is experimental for
now.
* "./autogen.sh --build-w32" does now also build a DLL for W32.
Translations are not yet provided for this platform.
* New error codes GPG_ERR_UNKNOWN_EXTN and GPG_ERR_UNKNOWN_CRIT_EXTN.
* New error code GPG_ERR_LOCKED.
* New translations included for France, Romania, and Vietnamese.
* Interface changes relative to the 1.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_UNKNOWN_EXTN NEW
GPG_ERR_UNKNOWN_CRIT_EXTN NEW
GPG_ERR_LOCKED NEW
gpg_err_init NEW
GPG_ERR_INITIALIZED NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 1.1 (2005-06-20)
----------------------------------------------
* Bug fixes.
Noteworthy changes in version 1.0 (2004-07-30)
----------------------------------------------
* Ported to Solaris 2.8.
* Added a new error source GPG_ERR_SOURCE_GSTI, and new error
codes GPG_ERR_PROTOCOL_VIOLATION and GPG_ERR_INV_MAC for this
source.
* Interface changes relative to the 0.7 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_SOURCE_GSTI NEW
GPG_ERR_PROTOCOL_VIOLATION NEW
GPG_ERR_INV_MAC NEW
GPG_ERR_INV_REQUEST NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.7 (2004-03-07)
----------------------------------------------
* libgpg-error can be built on systems where the errno macros do not
evaluate to plain numbers, but expressions. If you want to
cross-compile, you might have to set CC_FOR_BUILD, though.
* A new tool gpg-error to convert error numbers into symbols into
strings is provided.
* Interface changes relative to the 0.6 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_LOCALE_PROBLEM NEW
GPG_ERR_NOT_LOCKED NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.6 (2003-11-14)
----------------------------------------------
* German translation included.
* It is now possible to use the inline functions even for non C99
compliant compilers by given e.g. -DGPG_ERR_INLINE=inline when
compiling an application using this library. Note, that gcc will
use inline anyway.
* Interface changes relative to the 0.5 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_SOURCE_KSBA NEW
GPG_ERR_SOURCE_DIRMNGR NEW
GPG_ERR_TRUNCATED NEW
GPG_ERR_NO_ENCODING_METHOD NEW
GPG_ERR_NO_ENCRYPTION_SCHEME NEW
GPG_ERR_NO_SIGNATURE_SCHEME NEW
GPG_ERR_INV_ATTR NEW
GPG_ERR_NO_VALUE NEW
GPG_ERR_NOT_FOUND NEW
GPG_ERR_VALUE_NOT_FOUND NEW
GPG_ERR_SYNTAX NEW
GPG_ERR_INV_CRL NEW
GPG_ERR_BAD_BER NEW
GPG_ERR_INV_BER NEW
GPG_ERR_ELEMENT_NOT_FOUND NEW
GPG_ERR_IDENTIFIER_NOT_FOUND NEW
GPG_ERR_INV_TAG NEW
GPG_ERR_INV_LENGTH NEW
GPG_ERR_INV_KEYINFO NEW
GPG_ERR_UNEXPECTED_TAG NEW
GPG_ERR_NOT_DER_ENCODED, NEW
GPG_ERR_NO_CMS_OBJ NEW
GPG_ERR_INV_CMS_OBJ NEW
GPG_ERR_UNKNOWN_CMS_OBJ, NEW
GPG_ERR_UNSUPPORTED_CMS_OBJ NEW
GPG_ERR_UNSUPPORTED_ENCODING, NEW
GPG_ERR_UNSUPPORTED_CMS_VERSION NEW
GPG_ERR_UNKNOWN_ALGORITHM NEW
GPG_ERR_ENCODING_PROBLEM NEW
GPG_ERR_INV_STATE NEW
GPG_ERR_DUP_VALUE, NEW
GPG_ERR_MISSING_ACTION NEW
GPG_ERR_MODULE_NOT_FOUND NEW
GPG_ERR_INV_OID_STRING NEW
GPG_ERR_INV_TIME NEW
GPG_ERR_INV_CRL_OBJ NEW
GPG_ERR_UNSUPPORTED_CRL_VERSION NEW
GPG_ERR_INV_CERT_OBJ NEW
GPG_ERR_UNKNOWN_NAME NEW
GPG_ERR_BUFFER_TOO_SHORT. NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.5 (2003-10-06)
----------------------------------------------
* New thread safe interface gpg_strerror_r.
* New error code GPG_ERR_PIN_NOT_SYNCED has been added.
* Interface changes relative to the 0.4 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpg_strerror_r NEW
GPG_ERR_PIN_NOT_SYNCED NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.4 (2003-09-03)
----------------------------------------------
* Fixed another bug that prevented that system errors were created
correctly in the first place.
* Use inline in public header file only on C99 compilers.
Noteworthy changes in version 0.3 (2003-07-31)
----------------------------------------------
* Fixed bug that prevented that system errors were mapped to error
strings correctly.
Noteworthy changes in version 0.2 (2003-07-30)
----------------------------------------------
* Value of the error code GPG_ERR_CANCELED was fixed.
* New error codes GPG_ERR_WRONG_CARD, GPG_ERR_HARDWARE,
GPG_ERR_PIN_BLOCKED and GPG_ERR_USE_CONDITIONS have been added.
* The header file has been made C++ clean.
* AM_PATH_GPG_ERR has been fixed to work without explicit version
number.
* The header file now uses inline instead __inline__ for non-GNU
compilers.
Noteworthy changes in version 0.1 (2003-06-06)
----------------------------------------------
* Initial release.
Copyright 2003, 2004, 2005, 2010 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/configure.ac b/configure.ac
index cf0d37c..b155437 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,486 +1,491 @@
# configure.ac for libgpg-error
# Copyright (C) 2003, 2004, 2006, 2010, 2013, 2014 g10 Code GmbH
#
# This file is part of libgpg-error.
#
# libgpg-error 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.
#
# libgpg-error 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 General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
# (Process this file with autoconf to produce a configure script.)
# The following lines are used by ./autogen.sh.
AC_PREREQ(2.59)
min_automake_version="1.11"
# To build a release you need to create a tag with the version number
# (git tag -s libgpg-error-n.m) and run "./autogen.sh --force".
# Please bump the version number immediately after the release, do
# another commit, and a push so that the git magic is able to work.
# See below for the LT versions.
m4_define([mym4_version_major], [1])
m4_define([mym4_version_minor], [14])
# Below is m4 magic to extract and compute the revision number, the
# decimalized short revision number, a beta version string, and a flag
# indicating a development version (mym4_isgit). Note that the m4
# processing is done by autoconf and not during the configure run.
m4_define([mym4_version], [mym4_version_major.mym4_version_minor])
m4_define([mym4_revision],
m4_esyscmd([git rev-parse --short HEAD | tr -d '\n\r']))
m4_define([mym4_revision_dec],
m4_esyscmd_s([echo $((0x$(echo ]mym4_revision[|head -c 4)))]))
m4_define([mym4_betastring],
m4_esyscmd_s([git describe --match 'libgpg-error-[0-9].*[0-9]' --long|\
awk -F- '$4!=0{print"-beta"$4}']))
m4_define([mym4_isgit],m4_if(mym4_betastring,[],[no],[yes]))
m4_define([mym4_full_version],[mym4_version[]mym4_betastring])
AC_INIT([libgpg-error],[mym4_full_version],[http://bugs.gnupg.org])
# LT Version numbers, remember to change them just *before* a release.
# (Code changed: REVISION++)
# (Interfaces added/removed/changed: CURRENT++, REVISION=0)
# (Interfaces added: AGE++)
# (Interfaces removed: AGE=0)
# Note that added error codes don't constitute an interface change.
LIBGPG_ERROR_LT_CURRENT=11
LIBGPG_ERROR_LT_AGE=11
LIBGPG_ERROR_LT_REVISION=0
################################################
AC_SUBST(LIBGPG_ERROR_LT_CURRENT)
AC_SUBST(LIBGPG_ERROR_LT_AGE)
AC_SUBST(LIBGPG_ERROR_LT_REVISION)
VERSION_NUMBER=m4_esyscmd(printf "0x%02x%02x00" mym4_version_major \
mym4_version_minor)
AC_SUBST(VERSION_NUMBER)
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
AC_CONFIG_SRCDIR([src/err-sources.h.in])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_SILENT_RULES
# We need to know about the host architecture to avoid spurious
# warnings.
AC_CANONICAL_HOST
AB_INIT
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_AWK
AC_CHECK_TOOL(AR, ar, :)
AC_GNU_SOURCE
# Set some internal variables depending on the platform for later use.
have_w32_system=no
have_w64_system=no
have_w32ce_system=no
case "${host}" in
x86_64-*mingw32*)
have_w32_system=yes
have_w64_system=yes
;;
*-mingw32ce*)
have_w32_system=yes
have_w32ce_system=yes
;;
*-mingw32*)
have_w32_system=yes
;;
*)
;;
esac
if test "$have_w32_system" != yes; then
gl_THREADLIB_EARLY
fi
LT_PREREQ([2.2.6])
LT_INIT([win32-dll disable-static])
LT_LANG([Windows Resource])
# We need to compile and run a program on the build machine.
dnl The AC_PROG_CC_FOR_BUILD macro in the AC archive is broken for
dnl autoconf 2.57.
dnl AC_PROG_CC_FOR_BUILD
AC_MSG_CHECKING(for cc for build)
if test "$cross_compiling" = "yes"; then
CC_FOR_BUILD="${CC_FOR_BUILD-cc}"
else
CC_FOR_BUILD="${CC_FOR_BUILD-$CC}"
fi
AC_MSG_RESULT($CC_FOR_BUILD)
AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler])
AH_BOTTOM([
/* Force using of NLS for W32 even if no libintl has been found. This is
okay because we have our own gettext implementation for W32. */
#if defined(HAVE_W32_SYSTEM) && !defined(ENABLE_NLS)
#define ENABLE_NLS 1
#endif
+
+/* Connect the generic estream-printf.c to our framework. */
+#define _ESTREAM_PRINTF_REALLOC _gpgrt_realloc
+#define _ESTREAM_PRINTF_EXTRA_INCLUDE "gpgrt-int.h"
+
/* For building we need to define these macro. */
#define GPG_ERR_ENABLE_GETTEXT_MACROS 1
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define GPGRT_ENABLE_ES_MACROS 1
])
# Note, that autogen.sh greps for the next line.
AM_GNU_GETTEXT_VERSION([0.17])
AM_GNU_GETTEXT([external])
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h locale.h])
AC_FUNC_STRERROR_R
case "${host_os}" in
solaris*)
# All versions of Solaris from 2.4 have a thread-safe strerror().
# Since Solaris 10, in addition strerror_r() exists.
;;
*)
AC_CHECK_FUNC([strerror_r], [],
AC_MSG_WARN([[Without strerror_r, gpg_strerror_r might not be thread-safe]]))
;;
esac
AC_CHECK_FUNCS([flockfile vasprintf])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
#
# Setup gcc specific options
#
AC_MSG_NOTICE([checking for cc features])
if test "$GCC" = yes; then
# Check whether gcc does not emit a diagnostic for unknown -Wno-*
# options. This is the case for gcc >= 4.6
AC_MSG_CHECKING([if gcc ignores unknown -Wno-* options])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6 )
#kickerror
#endif]],[])],[_gcc_silent_wno=yes],[_gcc_silent_wno=no])
AC_MSG_RESULT($_gcc_silent_wno)
# Note that it is okay to use CFLAGS here because these are just
# warning options and the user should have a chance of overriding
# them.
if test "$USE_MAINTAINER_MODE" = "yes"; then
CFLAGS="$CFLAGS -O3 -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security"
if test x"$_gcc_silent_wno" = xyes ; then
_gcc_wopt=yes
else
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wno-missing-field-initializers"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],
[_gcc_wopt=yes],[_gcc_wopt=no])
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
fi
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -W -Wno-sign-compare -Wno-missing-field-initializers"
fi
AC_MSG_CHECKING([if gcc supports -Wdeclaration-after-statement])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wdeclaration-after-statement"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_wopt=yes,_gcc_wopt=no)
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -Wdeclaration-after-statement"
fi
else
CFLAGS="$CFLAGS -Wall"
fi
AC_MSG_CHECKING([if gcc supports -Wpointer-arith])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wpointer-arith"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_psign=yes,_gcc_psign=no)
AC_MSG_RESULT($_gcc_psign)
CFLAGS=$_gcc_cflags_save;
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
#
# Check whether the compiler supports the GCC style aligned attribute
#
AC_CACHE_CHECK([whether the GCC style aligned attribute is supported],
[gcry_cv_gcc_attribute_aligned],
[gcry_cv_gcc_attribute_aligned=no
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[[struct { int a; } foo __attribute__ ((aligned (16)));]])],
[gcry_cv_gcc_attribute_aligned=yes])])
if test "$gcry_cv_gcc_attribute_aligned" = "yes" ; then
AC_DEFINE(HAVE_GCC_ATTRIBUTE_ALIGNED,1,
[Defined if a GCC style "__attribute__ ((aligned (n))" is supported])
fi
#
# Check for ELF visibility support.
#
AC_CACHE_CHECK(whether the visibility attribute is supported,
gcry_cv_visibility_attribute,
[gcry_cv_visibility_attribute=no
AC_LANG_CONFTEST([AC_LANG_SOURCE(
[[int foo __attribute__ ((visibility ("hidden"))) = 1;
int bar __attribute__ ((visibility ("protected"))) = 1;
]])])
if ${CC-cc} -Werror -S conftest.c -o conftest.s \
1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ; then
if grep '\.hidden.*foo' conftest.s >/dev/null 2>&1 ; then
if grep '\.protected.*bar' conftest.s >/dev/null 2>&1; then
gcry_cv_visibility_attribute=yes
fi
fi
fi
])
if test "$gcry_cv_visibility_attribute" = "yes"; then
AC_CACHE_CHECK(for broken visibility attribute,
gcry_cv_broken_visibility_attribute,
[gcry_cv_broken_visibility_attribute=yes
AC_LANG_CONFTEST([AC_LANG_SOURCE(
[[int foo (int x);
int bar (int x) __asm__ ("foo")
__attribute__ ((visibility ("hidden")));
int bar (int x) { return x; }
]])])
if ${CC-cc} -Werror -S conftest.c -o conftest.s \
1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ; then
if grep '\.hidden@<:@ _@:>@foo' conftest.s >/dev/null 2>&1;
then
gcry_cv_broken_visibility_attribute=no
fi
fi
])
fi
if test "$gcry_cv_visibility_attribute" = "yes"; then
AC_CACHE_CHECK(for broken alias attribute,
gcry_cv_broken_alias_attribute,
[gcry_cv_broken_alias_attribute=yes
AC_LANG_CONFTEST([AC_LANG_SOURCE(
[[extern int foo (int x) __asm ("xyzzy");
int bar (int x) { return x; }
extern __typeof (bar) foo __attribute ((weak, alias ("bar")));
extern int dfoo;
extern __typeof (dfoo) dfoo __asm ("abccb");
int dfoo = 1;
]])])
if ${CC-cc} -Werror -S conftest.c -o conftest.s \
1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ; then
if grep 'xyzzy' conftest.s >/dev/null 2>&1 && \
grep 'abccb' conftest.s >/dev/null 2>&1; then
gcry_cv_broken_alias_attribute=no
fi
fi
])
fi
if test "$gcry_cv_visibility_attribute" = "yes"; then
AC_CACHE_CHECK(if gcc supports -fvisibility=hidden,
gcry_cv_gcc_has_f_visibility,
[gcry_cv_gcc_has_f_visibility=no
_gcc_cflags_save=$CFLAGS
CFLAGS="-fvisibility=hidden"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],
gcry_cv_gcc_has_f_visibility=yes)
CFLAGS=$_gcc_cflags_save;
])
fi
if test "$gcry_cv_visibility_attribute" = "yes" \
&& test "$gcry_cv_broken_visibility_attribute" != "yes" \
&& test "$gcry_cv_broken_alias_attribute" != "yes" \
&& test "$gcry_cv_gcc_has_f_visibility" = "yes"
then
AC_DEFINE(GPGRT_USE_VISIBILITY, 1,
[Define to use the GNU C visibility attribute.])
CFLAGS="$CFLAGS -fvisibility=hidden"
fi
#
# Check whether ld supports a version script.
# (Actually not a check but a list of systems which are known to support it.)
#
have_ld_version_script=no
case "${host}" in
*-*-linux*)
have_ld_version_script=yes
;;
*-*-gnu*)
have_ld_version_script=yes
;;
esac
AC_ARG_ENABLE([ld-version-script],
AC_HELP_STRING([--enable-ld-version-script],
[enable/disable use of linker version script.
(default is system dependent)]),
[have_ld_version_script=$enableval],
[ : ] )
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
#
# Check for thread library.
#
# Windows has always thread support; thus we don't bother to test for
# it as it may lead to false results when cross building.
if test "$have_w32_system" = yes; then
AC_DEFINE([USE_WINDOWS_THREADS], [1])
LIBTHREAD=
LTLIBTHREAD=
LIBMULTITHREAD=
LTLIBMULTITHREAD=
THREADLIB_CPPFLAGS=""
AC_SUBST([LIBTHREAD])
AC_SUBST([LTLIBTHREAD])
AC_SUBST([LIBMULTITHREAD])
AC_SUBST([LTLIBMULTITHREAD])
else
gl_LOCK
if test "$gl_threads_api" = posix; then
AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
fi
fi
#
# Prepare building of estream
#
estream_INIT
#
# Substitution used for gpg-error-config
#
GPG_ERROR_CONFIG_LIBS="-lgpg-error"
if test "x$LIBTHREAD" != x; then
GPG_ERROR_CONFIG_LIBS="${GPG_ERROR_CONFIG_LIBS} ${LIBTHREAD}"
fi
if test "x$LIBMULTITHREAD" != x; then
GPG_ERROR_CONFIG_MT_LIBS="${LIBMULTITHREAD}"
else
GPG_ERROR_CONFIG_MT_LIBS=""
fi
GPG_ERROR_CONFIG_CFLAGS=""
if test "x$THREADLIB_CPPFLAGS" != x; then
GPG_ERROR_CONFIG_MT_CFLAGS="${THREADLIB_CPPFLAGS}"
else
GPG_ERROR_CONFIG_MT_CFLAGS=""
fi
GPG_ERROR_CONFIG_ISUBDIRAFTER=""
GPG_ERROR_CONFIG_HOST="$host"
AC_SUBST(GPG_ERROR_CONFIG_LIBS)
AC_SUBST(GPG_ERROR_CONFIG_CFLAGS)
AC_SUBST(GPG_ERROR_CONFIG_MT_LIBS)
AC_SUBST(GPG_ERROR_CONFIG_MT_CFLAGS)
AC_SUBST(GPG_ERROR_CONFIG_ISUBDIRAFTER)
AC_SUBST(GPG_ERROR_CONFIG_HOST)
#
# Special defines for certain platforms
#
if test "$have_w32_system" = yes; then
AC_DEFINE(HAVE_W32_SYSTEM,1,[Defined if we run on a W32 API based system])
if test "$have_w64_system" = yes; then
AC_DEFINE(HAVE_W64_SYSTEM,1,[Defined if we run on 64 bit W32 API system])
fi
if test "$have_w32ce_system" = yes; then
AC_DEFINE(HAVE_W32CE_SYSTEM,1,[Defined if we run on WindowsCE])
GPG_ERROR_CONFIG_ISUBDIRAFTER="gpg-extra"
fi
fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
AM_CONDITIONAL(HAVE_W64_SYSTEM, test "$have_w64_system" = yes)
AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_system" = yes)
AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
AC_DEFINE_UNQUOTED(HOST_TRIPLET_STRING, "$host", [The host triplet])
#
# Provide information about the build.
#
BUILD_REVISION="mym4_revision"
AC_SUBST(BUILD_REVISION)
AC_DEFINE_UNQUOTED(BUILD_REVISION, "$BUILD_REVISION",
[GIT commit id revision used to build this package])
changequote(,)dnl
BUILD_FILEVERSION=`echo "$PACKAGE_VERSION"|sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
changequote([,])dnl
BUILD_FILEVERSION="${BUILD_FILEVERSION}0,mym4_revision_dec"
AC_SUBST(BUILD_FILEVERSION)
BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date`
AC_SUBST(BUILD_TIMESTAMP)
AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP",
[The time this package was configured for a build])
AC_ARG_ENABLE(languages,
[ --disable-languages do not build support for other languages than C])
AM_CONDITIONAL([LANGUAGES_SOME], [test "x$enable_languages" != xno])
#
# Substitution
#
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([po/Makefile.in m4/Makefile])
AC_CONFIG_FILES([src/Makefile tests/Makefile])
AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpg-error.asd])
AC_CONFIG_FILES([src/versioninfo.rc])
AC_CONFIG_FILES([src/gpg-error-config], [chmod +x src/gpg-error-config])
AC_OUTPUT
echo "
$PACKAGE_NAME-$PACKAGE_VERSION prepared for make
Revision: mym4_revision (mym4_revision_dec)
Platform: $host
"
if test "$gcry_cv_gcc_attribute_aligned" != "yes" ; then
cat <<G10EOF
***
*** Please note that your compiler does not support the GCC style
*** aligned attribute. Using this software may evoke bus errors.
***
G10EOF
fi
diff --git a/src/estream-printf.c b/src/estream-printf.c
index b1eb828..39a813f 100644
--- a/src/estream-printf.c
+++ b/src/estream-printf.c
@@ -1,1875 +1,1875 @@
/* estream-printf.c - Versatile mostly C-99 compliant printf formatting
* Copyright (C) 2007, 2008, 2009, 2010, 2012, 2014 g10 Code GmbH
*
* This file is part of Libestream.
*
* Libestream is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libestream is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libestream; if not, see <http://www.gnu.org/licenses/>.
*
* ALTERNATIVELY, Libestream may be distributed under the terms of the
* following license, in which case the provisions of this license are
* required INSTEAD OF the GNU General Public License. If you wish to
* allow use of your version of this file only under the terms of the
* GNU General Public License, and not to allow others to use your
* version of this file under the terms of the following license,
* indicate your decision by deleting this paragraph and the license
* below.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Required autoconf tests:
AC_TYPE_LONG_LONG_INT defines HAVE_LONG_LONG_INT
AC_TYPE_LONG_DOUBLE defines HAVE_LONG_DOUBLE
AC_TYPE_INTMAX_T defines HAVE_INTMAX_T
AC_TYPE_UINTMAX_T defines HAVE_UINTMAX_T
AC_CHECK_TYPES([ptrdiff_t]) defines HAVE_PTRDIFF_T
AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG
AC_CHECK_SIZEOF([void *]) defines SIZEOF_VOID_P
HAVE_LANGINFO_THOUSANDS_SEP
Note that the file estream.m4 provides the autoconf macro
ESTREAM_PRINTF_INIT which runs all required checks.
See estream-printf.h for ways to tune this code.
Missing stuff: wchar and wint_t
thousands_sep in pr_float.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
# define HAVE_W32_SYSTEM 1
# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
# define HAVE_W32CE_SYSTEM
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <stddef.h>
#include <assert.h>
#if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T)
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#ifdef HAVE_LANGINFO_THOUSANDS_SEP
#include <langinfo.h>
#endif
#ifdef HAVE_W32CE_SYSTEM
#include <gpg-error.h> /* ERRNO replacement. */
#endif
#ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE
# include _ESTREAM_PRINTF_EXTRA_INCLUDE
#endif
#include "estream-printf.h"
/* #define DEBUG 1 */
/* Allow redefinition of asprintf used realloc function. */
#if defined(_ESTREAM_PRINTF_REALLOC)
#define my_printf_realloc(a,b) _ESTREAM_PRINTF_REALLOC((a),(b))
#else
#define my_printf_realloc(a,b) fixed_realloc((a),(b))
#endif
/* A wrapper to set ERRNO. */
#ifdef HAVE_W32CE_SYSTEM
# define _set_errno(a) gpg_err_set_errno ((a))
#else
# define _set_errno(a) do { errno = (a); } while (0)
#endif
/* Calculate array dimension. */
#ifndef DIM
#define DIM(array) (sizeof (array) / sizeof (*array))
#endif
/* We allow for that many args without requiring malloced memory. */
#define DEFAULT_MAX_ARGSPECS 5
/* We allow for that many values without requiring malloced memory. */
#define DEFAULT_MAX_VALUES 8
/* We allocate this many new array argspec elements each time. */
#define ARGSPECS_BUMP_VALUE 10
/* Special values for the field width and the precision. */
#define NO_FIELD_VALUE (-1)
#define STAR_FIELD_VALUE (-2)
/* Bit valuues used for the conversion flags. */
#define FLAG_GROUPING 1
#define FLAG_LEFT_JUST 2
#define FLAG_PLUS_SIGN 4
#define FLAG_SPACE_PLUS 8
#define FLAG_ALT_CONV 16
#define FLAG_ZERO_PAD 32
/* Constants used the length modifiers. */
typedef enum
{
LENMOD_NONE = 0,
LENMOD_CHAR, /* "hh" */
LENMOD_SHORT, /* "h" */
LENMOD_LONG, /* "l" */
LENMOD_LONGLONG, /* "ll" */
LENMOD_INTMAX, /* "j" */
LENMOD_SIZET, /* "z" */
LENMOD_PTRDIFF, /* "t" */
LENMOD_LONGDBL /* "L" */
} lenmod_t;
/* All the conversion specifiers. */
typedef enum
{
CONSPEC_UNKNOWN = 0,
CONSPEC_DECIMAL,
CONSPEC_OCTAL,
CONSPEC_UNSIGNED,
CONSPEC_HEX,
CONSPEC_HEX_UP,
CONSPEC_FLOAT,
CONSPEC_FLOAT_UP,
CONSPEC_EXP,
CONSPEC_EXP_UP,
CONSPEC_F_OR_G,
CONSPEC_F_OR_G_UP,
CONSPEC_HEX_EXP,
CONSPEC_HEX_EXP_UP,
CONSPEC_CHAR,
CONSPEC_STRING,
CONSPEC_POINTER,
CONSPEC_STRERROR,
CONSPEC_BYTES_SO_FAR
} conspec_t;
/* Constants describing all the suppoorted types. Note that we list
all the types we know about even if certain types are not available
on this system. */
typedef enum
{
VALTYPE_UNSUPPORTED = 0, /* Artificial type for error detection. */
VALTYPE_CHAR,
VALTYPE_SCHAR,
VALTYPE_UCHAR,
VALTYPE_SHORT,
VALTYPE_USHORT,
VALTYPE_INT,
VALTYPE_UINT,
VALTYPE_LONG,
VALTYPE_ULONG,
VALTYPE_LONGLONG,
VALTYPE_ULONGLONG,
VALTYPE_DOUBLE,
VALTYPE_LONGDOUBLE,
VALTYPE_STRING,
VALTYPE_INTMAX,
VALTYPE_UINTMAX,
VALTYPE_SIZE,
VALTYPE_PTRDIFF,
VALTYPE_POINTER,
VALTYPE_CHAR_PTR,
VALTYPE_SCHAR_PTR,
VALTYPE_SHORT_PTR,
VALTYPE_INT_PTR,
VALTYPE_LONG_PTR,
VALTYPE_LONGLONG_PTR,
VALTYPE_INTMAX_PTR,
VALTYPE_SIZE_PTR,
VALTYPE_PTRDIFF_PTR
} valtype_t;
/* A union used to store the actual values. */
typedef union
{
char a_char;
signed char a_schar;
unsigned char a_uchar;
short a_short;
unsigned short a_ushort;
int a_int;
unsigned int a_uint;
long int a_long;
unsigned long int a_ulong;
#ifdef HAVE_LONG_LONG_INT
long long int a_longlong;
unsigned long long int a_ulonglong;
#endif
double a_double;
#ifdef HAVE_LONG_DOUBLE
long double a_longdouble;
#endif
const char *a_string;
#ifdef HAVE_INTMAX_T
intmax_t a_intmax;
#endif
#ifdef HAVE_UINTMAX_T
intmax_t a_uintmax;
#endif
size_t a_size;
#ifdef HAVE_PTRDIFF_T
ptrdiff_t a_ptrdiff;
#endif
void *a_void_ptr;
char *a_char_ptr;
signed char *a_schar_ptr;
short *a_short_ptr;
int *a_int_ptr;
long *a_long_ptr;
#ifdef HAVE_LONG_LONG_INT
long long int *a_longlong_ptr;
#endif
#ifdef HAVE_INTMAX_T
intmax_t *a_intmax_ptr;
#endif
size_t *a_size_ptr;
#ifdef HAVE_PTRDIFF_T
ptrdiff_t *a_ptrdiff_ptr;
#endif
} value_t;
/* An object used to keep track of a format option and arguments. */
struct argspec_s
{
size_t length; /* The length of these args including the percent. */
unsigned int flags; /* The conversion flags (bits defined by FLAG_foo). */
int width; /* The field width. */
int precision; /* The precision. */
lenmod_t lenmod; /* The length modifier. */
conspec_t conspec; /* The conversion specifier. */
int arg_pos; /* The position of the argument. This one may
be -1 to indicate that no value is expected
(e.g. for "%m"). */
int width_pos; /* The position of the argument for a field
width star's value. 0 for not used. */
int precision_pos; /* The position of the argument for the a
precision star's value. 0 for not used. */
valtype_t vt; /* The type of the corresponding argument. */
};
typedef struct argspec_s *argspec_t;
/* An object to build up a table of values and their types. */
struct valueitem_s
{
valtype_t vt; /* The type of the value. */
value_t value; /* The value. */
};
typedef struct valueitem_s *valueitem_t;
/* Not all systems have a C-90 compliant realloc. To cope with this
we use this simple wrapper. */
#ifndef _ESTREAM_PRINTF_REALLOC
static void *
fixed_realloc (void *a, size_t n)
{
if (!a)
return malloc (n);
if (!n)
{
free (a);
return NULL;
}
return realloc (a, n);
}
#endif /*!_ESTREAM_PRINTF_REALLOC*/
#ifdef DEBUG
static void
dump_argspecs (argspec_t arg, size_t argcount)
{
int idx;
for (idx=0; argcount; argcount--, arg++, idx++)
fprintf (stderr,
"%2d: len=%u flags=%u width=%d prec=%d mod=%d "
"con=%d vt=%d pos=%d-%d-%d\n",
idx,
(unsigned int)arg->length,
arg->flags,
arg->width,
arg->precision,
arg->lenmod,
arg->conspec,
arg->vt,
arg->arg_pos,
arg->width_pos,
arg->precision_pos);
}
#endif /*DEBUG*/
/* Set the vt field for ARG. */
static void
compute_type (argspec_t arg)
{
switch (arg->conspec)
{
case CONSPEC_UNKNOWN:
arg->vt = VALTYPE_UNSUPPORTED;
break;
case CONSPEC_DECIMAL:
switch (arg->lenmod)
{
case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break;
case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break;
case LENMOD_LONG: arg->vt = VALTYPE_LONG; break;
case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break;
case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break;
case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;
case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
default: arg->vt = VALTYPE_INT; break;
}
break;
case CONSPEC_OCTAL:
case CONSPEC_UNSIGNED:
case CONSPEC_HEX:
case CONSPEC_HEX_UP:
switch (arg->lenmod)
{
case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break;
case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break;
case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break;
case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break;
case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break;
case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;
case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
default: arg->vt = VALTYPE_UINT; break;
}
break;
case CONSPEC_FLOAT:
case CONSPEC_FLOAT_UP:
case CONSPEC_EXP:
case CONSPEC_EXP_UP:
case CONSPEC_F_OR_G:
case CONSPEC_F_OR_G_UP:
case CONSPEC_HEX_EXP:
case CONSPEC_HEX_EXP_UP:
switch (arg->lenmod)
{
case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break;
case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break;
default: arg->vt = VALTYPE_DOUBLE; break;
}
break;
case CONSPEC_CHAR:
arg->vt = VALTYPE_INT;
break;
case CONSPEC_STRING:
arg->vt = VALTYPE_STRING;
break;
case CONSPEC_POINTER:
arg->vt = VALTYPE_POINTER;
break;
case CONSPEC_STRERROR:
arg->vt = VALTYPE_STRING;
break;
case CONSPEC_BYTES_SO_FAR:
switch (arg->lenmod)
{
case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break;
case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break;
case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break;
case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break;
case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break;
case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break;
case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break;
default: arg->vt = VALTYPE_INT_PTR; break;
}
break;
}
}
/* Parse the FORMAT string and populate the specification array stored
at the address ARGSPECS_ADDR. The caller has provided enough space
to store up to MAX_ARGSPECS in that buffer. The function may
however ignore the provided buffer and malloc a larger one. On
- success the addrrss of that larger buffer will be stored at
+ success the address 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
_gpgrt_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
_gpgrt_estream_printf (const char *format, ...)
{
int rc;
va_list arg_ptr;
va_start (arg_ptr, format);
rc = _gpgrt_estream_format (plain_stdio_out, stderr, format, arg_ptr);
va_end (arg_ptr);
return rc;
}
/* A replacement for fprintf. */
int
_gpgrt_estream_fprintf (FILE *fp, const char *format, ...)
{
int rc;
va_list arg_ptr;
va_start (arg_ptr, format);
rc = _gpgrt_estream_format (plain_stdio_out, fp, format, arg_ptr);
va_end (arg_ptr);
return rc;
}
/* A replacement for vfprintf. */
int
_gpgrt_estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
{
return _gpgrt_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
_gpgrt_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 = _gpgrt_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
_gpgrt_estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
{
int rc;
va_list arg_ptr;
va_start (arg_ptr, format);
rc = _gpgrt_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 version of vasprintf
-1 will be returned on error and NULL stored at BUFP. On success
the number of bytes printed will be returned. */
int
_gpgrt_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 = _gpgrt_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
_gpgrt_estream_asprintf (char **bufp, const char *format, ...)
{
int rc;
va_list arg_ptr;
va_start (arg_ptr, format);
rc = _gpgrt_estream_vasprintf (bufp, format, arg_ptr);
va_end (arg_ptr);
return rc;
}
/* 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 *
_gpgrt_estream_bsprintf (const char *format, ...)
{
int rc;
va_list ap;
char *buf;
va_start (ap, format);
rc = _gpgrt_estream_vasprintf (&buf, format, ap);
va_end (ap);
if (rc < 0)
return NULL;
return buf;
}
diff --git a/src/estream.c b/src/estream.c
index cf3067b..7a5646e 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -1,4392 +1,4389 @@
/* estream.c - Extended Stream I/O Library
* Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011,
* 2014 g10 Code GmbH
*
* This file is part of Libestream.
*
* Libestream is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libestream is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libestream; if not, see <http://www.gnu.org/licenses/>.
*
* ALTERNATIVELY, Libestream may be distributed under the terms of the
* following license, in which case the provisions of this license are
* required INSTEAD OF the GNU General Public License. If you wish to
* allow use of your version of this file only under the terms of the
* GNU General Public License, and not to allow others to use your
* version of this file under the terms of the following license,
* indicate your decision by deleting this paragraph and the license
* below.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef USE_ESTREAM_SUPPORT_H
# include <estream-support.h>
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
# define HAVE_W32_SYSTEM 1
# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
# define HAVE_W32CE_SYSTEM
# endif
#endif
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <stddef.h>
#include <assert.h>
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
#endif
#include "gpgrt-int.h"
#include "estream-printf.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifdef HAVE_W32_SYSTEM
# define S_IRGRP S_IRUSR
# define S_IROTH S_IRUSR
# define S_IWGRP S_IWUSR
# define S_IWOTH S_IWUSR
# define S_IXGRP S_IXUSR
# define S_IXOTH S_IXUSR
#endif
#ifdef HAVE_W32CE_SYSTEM
# define _set_errno(a) gpg_err_set_errno ((a))
/* Setmode is missing in cegcc but available since CE 5.0. */
int _setmode (int handle, int mode);
# define setmode(a,b) _setmode ((a),(b))
#else
# define _set_errno(a) do { errno = (a); } while (0)
#endif
#ifdef HAVE_W32_SYSTEM
# define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1)) /* ?? FIXME. */
#else
# define IS_INVALID_FD(a) ((a) == -1)
#endif
/* Generally used types. */
typedef void *(*func_realloc_t) (void *mem, size_t size);
typedef void (*func_free_t) (void *mem);
/* Buffer management layer. */
#define BUFFER_BLOCK_SIZE BUFSIZ
#define BUFFER_UNREAD_SIZE 16
/* 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 _gpgrt_stream_internal
{
unsigned char buffer[BUFFER_BLOCK_SIZE];
unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
gpgrt_lock_t lock; /* Lock. */
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;
gpgrt_cookie_read_function_t func_read;
gpgrt_cookie_write_function_t func_write;
gpgrt_cookie_seek_function_t func_seek;
gpgrt_cookie_close_function_t func_close;
cookie_ioctl_function_t func_ioctl;
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 _gpgrt_stream_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;
/* A lock object for the estream list and the custom_std_fds array. */
GPGRT_LOCK_DEFINE (estream_list_lock);
/* 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];
/* Functions called before and after blocking syscalls. */
static void (*pre_syscall_func)(void);
static void (*post_syscall_func)(void);
/* 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);
+ return _gpgrt_malloc (n);
}
static void *
mem_realloc (void *p, size_t n)
{
- if (!p)
- return mem_alloc (n);
- return realloc (p, n);
+ return _gpgrt_realloc (p, n);
}
static void
mem_free (void *p)
{
if (p)
- free (p);
+ _gpgrt_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*/
/* Replacement fucntions. */
#ifndef HAVE_MEMRCHR
static void *
memrchr (const void *buffer, int c, size_t n)
{
const unsigned char *p = buffer;
for (p += n; n ; n--)
if (*--p == c)
return (void *)p;
return NULL;
}
#endif /*HAVE_MEMRCHR*/
/*
* 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 _GPGRT__RESTRICT stream)
{
int rc;
if (!stream->intern->samethread)
{
dbg_lock_1 ("enter init_stream_lock for %p\n", stream);
memset (&stream->intern->lock, 0 , sizeof stream->intern->lock);
rc = _gpgrt_lock_init (&stream->intern->lock);
dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc);
}
else
rc = 0;
return rc;
}
static void
lock_stream (estream_t _GPGRT__RESTRICT stream)
{
if (!stream->intern->samethread)
{
dbg_lock_1 ("enter lock_stream for %p\n", stream);
_gpgrt_lock_lock (&stream->intern->lock);
dbg_lock_1 ("leave lock_stream for %p\n", stream);
}
}
static int
trylock_stream (estream_t _GPGRT__RESTRICT stream)
{
int rc;
if (!stream->intern->samethread)
{
dbg_lock_1 ("enter trylock_stream for %p\n", stream);
rc = _gpgrt_lock_trylock (&stream->intern->lock)? 0 : -1;
dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc);
}
else
rc = 0;
return rc;
}
static void
unlock_stream (estream_t _GPGRT__RESTRICT stream)
{
if (!stream->intern->samethread)
{
dbg_lock_1 ("enter unlock_stream for %p\n", stream);
_gpgrt_lock_unlock (&stream->intern->lock);
dbg_lock_1 ("leave unlock_stream for %p\n", stream);
}
}
static void
lock_list (void)
{
dbg_lock_0 ("enter lock_list\n");
_gpgrt_lock_lock (&estream_list_lock);
dbg_lock_0 ("leave lock_list\n");
}
static void
unlock_list (void)
{
dbg_lock_0 ("enter unlock_list\n");
_gpgrt_lock_unlock (&estream_list_lock);
dbg_lock_0 ("leave unlock_list\n");
}
#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 ();
}
static void
do_deinit (void)
{
/* Flush all streams. */
_gpgrt_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. */
/* Reset the syscall clamp. */
pre_syscall_func = NULL;
post_syscall_func = NULL;
}
/*
* Initialization.
*/
int
_gpgrt_es_init (void)
{
static int initialized;
if (!initialized)
{
initialized = 1;
atexit (do_deinit);
}
return 0;
}
/* Register the syscall clamp. These two functions are called
immediately before and after a possible blocking system call. This
should be used before any I/O happens. The function is commonly
used with the nPth library:
- gpgrt_set_syscall_clamp (npth_protect, npth_unprotect);
+ gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
These functions may not modify ERRNO.
*/
void
_gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void))
{
pre_syscall_func = pre;
post_syscall_func = post;
}
/*
* 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 *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
unsigned char *_GPGRT__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 gpgrt_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))
{
_gpgrt_yield ();
bytes_read = 0;
}
else
{
if (pre_syscall_func)
pre_syscall_func ();
do
{
bytes_read = read (file_cookie->fd, buffer, size);
}
while (bytes_read == -1 && errno == EINTR);
if (post_syscall_func)
post_syscall_func ();
}
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))
{
_gpgrt_yield ();
bytes_written = size; /* Yeah: Success writing to the bit bucket. */
}
else
{
if (pre_syscall_func)
pre_syscall_func ();
do
{
bytes_written = write (file_cookie->fd, buffer, size);
}
while (bytes_written == -1 && errno == EINTR);
if (post_syscall_func)
post_syscall_func ();
}
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
{
if (pre_syscall_func)
pre_syscall_func ();
offset_new = lseek (file_cookie->fd, *offset, whence);
if (post_syscall_func)
post_syscall_func ();
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 gpgrt_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)
{
_gpgrt_yield ();
bytes_read = 0;
}
else
{
if (pre_syscall_func)
pre_syscall_func ();
do
{
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));
bytes_read = -1;
}
}
else
bytes_read = (int)nread;
}
while (bytes_read == -1 && errno == EINTR);
if (post_syscall_func)
post_syscall_func ();
}
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)
{
_gpgrt_yield ();
bytes_written = size; /* Yeah: Success writing to the bit bucket. */
}
else
{
if (pre_syscall_func)
pre_syscall_func ();
do
{
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;
}
while (bytes_written == -1 && errno == EINTR);
if (post_syscall_func)
post_syscall_func ();
}
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 (pre_syscall_func)
pre_syscall_func ();
if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
{
_set_errno (map_w32_to_errno (GetLastError ()));
if (post_syscall_func)
post_syscall_func ();
return -1;
}
if (post_syscall_func)
post_syscall_func ();
#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 gpgrt_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)
{
if (pre_syscall_func)
pre_syscall_func ();
bytes_read = fread (buffer, 1, size, file_cookie->fp);
if (post_syscall_func)
post_syscall_func ();
}
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)
{
if (pre_syscall_func)
pre_syscall_func ();
#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);
if (post_syscall_func)
post_syscall_func ();
}
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 (pre_syscall_func)
pre_syscall_func ();
if ( fseek (file_cookie->fp, (long int)*offset, whence) )
{
/* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
/* errno,strerror (errno)); */
if (post_syscall_func)
post_syscall_func ();
return -1;
}
offset_new = ftell (file_cookie->fp);
if (post_syscall_func)
post_syscall_func ();
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)
{
if (pre_syscall_func)
pre_syscall_func ();
fflush (fp_cookie->fp);
if (post_syscall_func)
post_syscall_func ();
err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
}
else
err = 0;
mem_free (fp_cookie);
}
else
err = 0;
return err;
}
static gpgrt_cookie_io_functions_t estream_functions_fp =
{
es_func_fp_read,
es_func_fp_write,
es_func_fp_seek,
es_func_fp_destroy
};
/* Implementation of file I/O. */
/* Create function for objects identified by a file name. */
static int
func_file_create (void **cookie, int *filedes,
const char *path, unsigned int modeflags, unsigned int cmode)
{
estream_cookie_fd_t file_cookie;
int err;
int fd;
err = 0;
fd = -1;
file_cookie = mem_alloc (sizeof (*file_cookie));
if (! file_cookie)
{
err = -1;
goto out;
}
fd = open (path, modeflags, cmode);
if (fd == -1)
{
err = -1;
goto out;
}
#ifdef HAVE_DOSISH_SYSTEM
/* Make sure it is in binary mode if requested. */
if ( (modeflags & O_BINARY) )
setmode (fd, O_BINARY);
#endif
file_cookie->fd = fd;
file_cookie->no_close = 0;
*cookie = file_cookie;
*filedes = fd;
out:
if (err)
mem_free (file_cookie);
return err;
}
/* Parse the mode flags of fopen et al. In addition to the POSIX
defined mode flags keyword parameters are supported. These are
key/value pairs delimited by comma and optional white spaces.
Keywords and values may not contain a comma or white space; unknown
keywords are skipped. Supported keywords are:
mode=<string>
Creates a file and gives the new file read and write permissions
for the user and read permission for the group. The format of
the string is the same as shown by the -l option of the ls(1)
command. However the first letter must be a dash and it is
allowed to leave out trailing dashes. If this keyword parameter
is not given the default mode for creating files is "-rw-rw-r--"
(664). Note that the system still applies the current umask to
the mode when crating a file. Example:
"wb,mode=-rw-r--"
samethread
Assumes that the object is only used by the creating thread and
disables any internal locking. This keyword is also found on
IBM systems.
Note: R_CMODE is optional because is only required by functions
which are able to creat a file. */
static int
parse_mode (const char *modestr,
unsigned int *modeflags, int *samethread,
unsigned int *r_cmode)
{
unsigned int omode, oflags, cmode;
int got_cmode = 0;
*samethread = 0;
switch (*modestr)
{
case 'r':
omode = O_RDONLY;
oflags = 0;
break;
case 'w':
omode = O_WRONLY;
oflags = O_TRUNC | O_CREAT;
break;
case 'a':
omode = O_WRONLY;
oflags = O_APPEND | O_CREAT;
break;
default:
_set_errno (EINVAL);
return -1;
}
for (modestr++; *modestr; modestr++)
{
switch (*modestr)
{
case '+':
omode = O_RDWR;
break;
case 'b':
oflags |= O_BINARY;
break;
case 'x':
oflags |= O_EXCL;
break;
case ',':
goto keyvalue;
default: /* Ignore unknown flags. */
break;
}
}
keyvalue:
/* Parse key/value pairs (similar to fopen on mainframes). */
for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ","))
{
modestr++;
modestr += strspn (modestr, " \t");
if (!strncmp (modestr, "mode=", 5))
{
static struct {
char letter;
unsigned int value;
} table[] = { { '-', 0 },
{ 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR },
{ 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP },
{ 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }};
int idx;
got_cmode = 1;
modestr += 5;
/* For now we only support a string as used by ls(1) and no
octal numbers. The first character must be a dash. */
for (idx=0; idx < 10 && *modestr; idx++, modestr++)
{
if (*modestr == table[idx].letter)
cmode |= table[idx].value;
else if (*modestr != '-')
break;
}
if (*modestr && !strchr (" \t,", *modestr))
{
_set_errno (EINVAL);
return -1;
}
}
else if (!strncmp (modestr, "samethread", 10))
{
modestr += 10;
if (*modestr && !strchr (" \t,", *modestr))
{
_set_errno (EINVAL);
return -1;
}
*samethread = 1;
}
}
if (!got_cmode)
cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
*modeflags = (omode | oflags);
if (r_cmode)
*r_cmode = cmode;
return 0;
}
/*
* Low level stream functionality.
*/
static int
es_fill (estream_t stream)
{
size_t bytes_read = 0;
int err;
if (!stream->intern->func_read)
{
_set_errno (EOPNOTSUPP);
err = -1;
}
else
{
gpgrt_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)
{
gpgrt_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,
gpgrt_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)
{
gpgrt_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,
gpgrt_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);
_gpgrt_lock_destroy (&stream_new->intern->lock);
mem_free (stream_new->intern);
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);
_gpgrt_lock_destroy (&stream->intern->lock);
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 _GPGRT__RESTRICT stream,
unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
{
gpgrt_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 _GPGRT__RESTRICT stream,
unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_read, size_t *_GPGRT__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 _GPGRT__RESTRICT stream,
unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_read, size_t *_GPGRT__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 _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT buffer_arg,
size_t bytes_to_read, size_t *_GPGRT__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 _GPGRT__RESTRICT stream,
const unsigned char *_GPGRT__RESTRICT data, size_t data_n,
size_t *_GPGRT__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 _GPGRT__RESTRICT stream, off_t offset, int whence,
off_t *_GPGRT__RESTRICT offset_new)
{
gpgrt_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 _GPGRT__RESTRICT stream,
const unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
{
gpgrt_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 _GPGRT__RESTRICT stream,
const unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_write, size_t *_GPGRT__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 _GPGRT__RESTRICT stream,
const unsigned char *_GPGRT__RESTRICT buffer,
size_t bytes_to_write, size_t *_GPGRT__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 _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer,
size_t bytes_to_write, size_t *_GPGRT__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 _GPGRT__RESTRICT stream, unsigned char **_GPGRT__RESTRICT data,
size_t *_GPGRT__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 _GPGRT__RESTRICT stream, size_t max_length,
char *_GPGRT__RESTRICT *_GPGRT__RESTRICT line,
size_t *_GPGRT__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 = _gpgrt_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 = _gpgrt_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 = _gpgrt_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 _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, va_list ap)
{
int rc;
stream->intern->print_ntotal = 0;
rc = _gpgrt_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 _GPGRT__RESTRICT stream,
char *_GPGRT__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 _GPGRT__RESTRICT stream, void *_GPGRT__RESTRICT opaque_new,
void **_GPGRT__RESTRICT opaque_old)
{
if (opaque_old)
*opaque_old = stream->intern->opaque;
if (opaque_new)
stream->intern->opaque = opaque_new;
}
/* API. */
estream_t
_gpgrt_fopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__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
_gpgrt_mopen (void *_GPGRT__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 *_GPGRT__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
_gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__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
_gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode,
const void *data, size_t datalen)
{
estream_t stream;
if (memlimit && memlimit < datalen)
memlimit = datalen;
stream = _gpgrt_fopenmem (memlimit, mode);
if (stream && data && datalen)
{
if (es_writen (stream, data, datalen, NULL))
{
int saveerrno = errno;
_gpgrt_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
_gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
const char *_GPGRT__RESTRICT mode,
gpgrt_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;
}
static 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
_gpgrt_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
_gpgrt_fdopen_nc (int filedes, const char *mode)
{
return do_fdopen (filedes, mode, 1, 0);
}
static 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
_gpgrt_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
_gpgrt_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
_gpgrt_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
_gpgrt_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. This internal version uses a double
dash inside its name. */
void
_gpgrt__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.
This internal version uses a double dash inside its name. */
estream_t
_gpgrt__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
_gpgrt_freopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode,
estream_t _GPGRT__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
_gpgrt_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. */
+ gpgrt_free. */
int
_gpgrt_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
_gpgrt_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
_gpgrt_fileno_unlocked (estream_t stream)
{
es_syshd_t syshd;
if (_gpgrt_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
_gpgrt_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
_gpgrt_flockfile (estream_t stream)
{
lock_stream (stream);
}
int
_gpgrt_ftrylockfile (estream_t stream)
{
return trylock_stream (stream);
}
void
_gpgrt_funlockfile (estream_t stream)
{
unlock_stream (stream);
}
int
_gpgrt_fileno (estream_t stream)
{
int ret;
lock_stream (stream);
ret = _gpgrt_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
_gpgrt_syshd (estream_t stream, es_syshd_t *syshd)
{
int ret;
lock_stream (stream);
ret = _gpgrt_syshd_unlocked (stream, syshd);
unlock_stream (stream);
return ret;
}
int
_gpgrt_feof_unlocked (estream_t stream)
{
return es_get_indicator (stream, 0, 1);
}
int
_gpgrt_feof (estream_t stream)
{
int ret;
lock_stream (stream);
ret = _gpgrt_feof_unlocked (stream);
unlock_stream (stream);
return ret;
}
int
_gpgrt_ferror_unlocked (estream_t stream)
{
return es_get_indicator (stream, 1, 0);
}
int
_gpgrt_ferror (estream_t stream)
{
int ret;
lock_stream (stream);
ret = _gpgrt_ferror_unlocked (stream);
unlock_stream (stream);
return ret;
}
void
_gpgrt_clearerr_unlocked (estream_t stream)
{
es_set_indicators (stream, 0, 0);
}
void
_gpgrt_clearerr (estream_t stream)
{
lock_stream (stream);
_gpgrt_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
_gpgrt_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
_gpgrt_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
_gpgrt_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
_gpgrt_ftell (estream_t stream)
{
long int ret;
lock_stream (stream);
ret = es_offset_calculate (stream);
unlock_stream (stream);
return ret;
}
off_t
_gpgrt_ftello (estream_t stream)
{
off_t ret = -1;
lock_stream (stream);
ret = es_offset_calculate (stream);
unlock_stream (stream);
return ret;
}
void
_gpgrt_rewind (estream_t stream)
{
lock_stream (stream);
es_seek (stream, 0L, SEEK_SET, NULL);
es_set_indicators (stream, 0, -1);
unlock_stream (stream);
}
int
_gpgrt__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
_gpgrt__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
_gpgrt_fgetc (estream_t stream)
{
int ret;
lock_stream (stream);
ret = _gpgrt_getc_unlocked (stream);
unlock_stream (stream);
return ret;
}
int
_gpgrt_fputc (int c, estream_t stream)
{
int ret;
lock_stream (stream);
ret = _gpgrt_putc_unlocked (c, stream);
unlock_stream (stream);
return ret;
}
int
_gpgrt_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
_gpgrt_read (estream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT buffer, size_t bytes_to_read,
size_t *_GPGRT__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
_gpgrt_write (estream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write,
size_t *_GPGRT__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
_gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
estream_t _GPGRT__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
_gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
estream_t _GPGRT__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 *
_gpgrt_fgets (char *_GPGRT__RESTRICT buffer, int length,
estream_t _GPGRT__RESTRICT stream)
{
unsigned char *s = (unsigned char*)buffer;
int c;
if (!length)
return NULL;
c = EOF;
lock_stream (stream);
while (length > 1 && (c = _gpgrt_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
_gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s,
estream_t _GPGRT__RESTRICT stream)
{
size_t length;
int err;
length = strlen (s);
err = es_writen (stream, s, length, NULL);
return err ? EOF : 0;
}
int
_gpgrt_fputs (const char *_GPGRT__RESTRICT s, estream_t _GPGRT__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
_gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr,
size_t *_GPGRT__RESTRICT n, estream_t _GPGRT__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.
+ released using gpgrt_free.
*/
ssize_t
_gpgrt_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 = _gpgrt_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=_gpgrt_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
-_gpgrt_free (void *a)
-{
- mem_free (a);
-}
+/* Wrapper around free() to match the memory allocation system used by
+ estream. Should be used for all buffers returned to the caller by
+ libestream. If a custom allocation handler has been set with
+ gpgrt_set_alloc_func that register function may be used
+ instead. This function has been moved to init.c. */
+/* void */
+/* _gpgrt_free (void *a) */
+/* { */
+/* mem_free (a); */
+/* } */
int
_gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format,
va_list ap)
{
return es_print (stream, format, ap);
}
int
_gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format,
va_list ap)
{
int ret;
lock_stream (stream);
ret = es_print (stream, format, ap);
unlock_stream (stream);
return ret;
}
int
_gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
{
int ret;
va_list ap;
va_start (ap, format);
ret = es_print (stream, format, ap);
va_end (ap);
return ret;
}
int
_gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__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;
}
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
_gpgrt_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
_gpgrt_setvbuf (estream_t _GPGRT__RESTRICT stream,
char *_GPGRT__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;
}
/* 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
_gpgrt_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
_gpgrt_opaque_set (estream_t stream, void *opaque)
{
lock_stream (stream);
es_opaque_ctrl (stream, opaque, NULL);
unlock_stream (stream);
}
void *
_gpgrt_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
_gpgrt_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 *
_gpgrt_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
_gpgrt_write_sanitized (estream_t _GPGRT__RESTRICT stream,
const void * _GPGRT__RESTRICT buffer, size_t length,
const char * delimiters,
size_t * _GPGRT__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 == '\\')))
{
_gpgrt_putc_unlocked ('\\', stream);
count++;
if (*p == '\n')
{
_gpgrt_putc_unlocked ('n', stream);
count++;
}
else if (*p == '\r')
{
_gpgrt_putc_unlocked ('r', stream);
count++;
}
else if (*p == '\f')
{
_gpgrt_putc_unlocked ('f', stream);
count++;
}
else if (*p == '\v')
{
_gpgrt_putc_unlocked ('v', stream);
count++;
}
else if (*p == '\b')
{
_gpgrt_putc_unlocked ('b', stream);
count++;
}
else if (!*p)
{
_gpgrt_putc_unlocked('0', stream);
count++;
}
else
{
_gpgrt_fprintf_unlocked (stream, "x%02x", *p);
count += 3;
}
}
else
{
_gpgrt_putc_unlocked (*p, stream);
count++;
}
}
if (bytes_written)
*bytes_written = count;
ret = _gpgrt_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
_gpgrt_write_hexstring (estream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
int reserved, size_t *_GPGRT__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--)
{
_gpgrt_putc_unlocked ( tohex ((*s>>4)&15), stream);
_gpgrt_putc_unlocked ( tohex (*s&15), stream);
count += 2;
}
if (bytes_written)
*bytes_written = count;
ret = _gpgrt_ferror_unlocked (stream)? -1 : 0;
unlock_stream (stream);
return ret;
#undef tohex
}
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index b318d61..ac20a69 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -1,140 +1,140 @@
/* libgpg-error.def - Exported symbols for W32
* Copyright (C) 2014 g10 Code GmbH
*
* This file is part of libgpg-error.
*
* libgpg-error 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.
*
* libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
*
* Note: This file should be updated manually and the ordinals shall
* never be changed. Also check gpg-error.vers and visibility.h.
*
* This file needs to be pre-processed.
*/
#include <config.h>
EXPORTS
gpg_strerror @1
gpg_strerror_r @2
gpg_strsource @3
gpg_err_code_from_errno @4
gpg_err_code_to_errno @5
/* @6 - Not anymore used. */
gpg_err_code_from_syserror @7
gpg_err_set_errno @8
#ifdef HAVE_W32CE_SYSTEM
_gpg_w32ce_get_errno @9
_gpg_w32ce_strerror @10
#endif
#ifdef HAVE_W32_SYSTEM
_gpg_w32_bindtextdomain @11
_gpg_w32_textdomain @12
_gpg_w32_gettext @13
_gpg_w32_dgettext @14
_gpg_w32_dngettext @15
_gpg_w32_gettext_localename @16
_gpg_w32_gettext_use_utf8 @17
#endif
/* @18 - Not anymore used. */
gpg_error_check_version @19
gpgrt_lock_init @20
gpgrt_lock_lock @21
gpgrt_lock_unlock @22
gpgrt_lock_destroy @23
gpgrt_yield @24
gpgrt_lock_trylock @25
gpgrt_set_syscall_clamp @26
gpgrt_fopen @27
gpgrt_mopen @28
gpgrt_fopenmem @29
gpgrt_fopenmem_init @30
gpgrt_fdopen @31
gpgrt_fdopen_nc @32
gpgrt_sysopen @33
gpgrt_sysopen_nc @34
gpgrt_fpopen @35
gpgrt_fpopen_nc @36
gpgrt_freopen @37
gpgrt_fopencookie @38
gpgrt_fclose @39
gpgrt_fclose_snatch @40
gpgrt_onclose @41
gpgrt_fileno @42
gpgrt_fileno_unlocked @43
gpgrt_syshd @44
gpgrt_syshd_unlocked @45
_gpgrt_set_std_fd @46
_gpgrt_get_std_stream @47
gpgrt_flockfile @48
gpgrt_ftrylockfile @49
gpgrt_funlockfile @50
gpgrt_feof @51
gpgrt_feof_unlocked @52
gpgrt_ferror @53
gpgrt_ferror_unlocked @54
gpgrt_clearerr @55
gpgrt_clearerr_unlocked @56
gpgrt_fflush @57
gpgrt_fseek @58
gpgrt_fseeko @59
gpgrt_ftell @60
gpgrt_ftello @61
gpgrt_rewind @62
gpgrt_fgetc @63
_gpgrt_getc_underflow @64
gpgrt_fputc @65
_gpgrt_putc_overflow @66
gpgrt_ungetc @67
gpgrt_read @68
gpgrt_write @69
gpgrt_write_sanitized @70
gpgrt_write_hexstring @71
gpgrt_fread @72
gpgrt_fwrite @73
gpgrt_fgets @74
gpgrt_fputs @75
gpgrt_fputs_unlocked @76
gpgrt_getline @77
gpgrt_read_line @78
gpgrt_free @79
gpgrt_fprintf @80
gpgrt_fprintf_unlocked @81
gpgrt_printf @82
gpgrt_printf_unlocked @83
gpgrt_vfprintf @84
gpgrt_vfprintf_unlocked @85
gpgrt_setvbuf @86
gpgrt_setbuf @87
gpgrt_set_binary @88
gpgrt_tmpfile @89
gpgrt_opaque_set @90
gpgrt_opaque_get @91
gpgrt_fname_set @92
gpgrt_fname_get @93
gpgrt_asprintf @94
gpgrt_vasprintf @95
gpgrt_bsprintf @96
gpgrt_vbsprintf @97
gpgrt_snprintf @98
gpgrt_vsnprintf @99
gpgrt_check_version @100
gpg_err_init @101
gpg_err_deinit @102
-
+ gpgrt_set_alloc_func @103
;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index 8c008ac..4b1c0a0 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1,694 +1,698 @@
/* gpg-error.h - Public interface to libgpg-error. -*- c -*-
Copyright (C) 2003, 2004, 2010, 2013, 2014 g10 Code GmbH
This file is part of libgpg-error.
libgpg-error 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.
libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
@configure_input@
*/
#ifndef GPG_ERROR_H
#define GPG_ERROR_H 1
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef __GNUC__
#define GPG_ERR_INLINE __inline__
#elif _MSC_VER >= 1300
#define GPG_ERR_INLINE __inline
#elif __STDC_VERSION__ >= 199901L
#define GPG_ERR_INLINE inline
#else
#ifndef GPG_ERR_INLINE
#define GPG_ERR_INLINE
#endif
#endif
#ifdef __cplusplus
extern "C" {
#if 0 /* just to make Emacs auto-indent happy */
}
#endif
#endif /* __cplusplus */
/* The GnuPG project consists of many components. Error codes are
exchanged between all components. The common error codes and their
user-presentable descriptions are kept into a shared library to
allow adding new error codes and components without recompiling any
of the other components. The interface will not change in a
backward incompatible way.
An error code together with an error source build up an error
value. As the error value is been passed from one component to
another, it preserver the information about the source and nature
of the error.
A component of the GnuPG project can define the following macros to
tune the behaviour of the library:
GPG_ERR_SOURCE_DEFAULT: Define to an error source of type
gpg_err_source_t to make that source the default for gpg_error().
Otherwise GPG_ERR_SOURCE_UNKNOWN is used as default.
GPG_ERR_ENABLE_GETTEXT_MACROS: Define to provide macros to map the
internal gettext API to standard names. This has only an effect on
Windows platforms.
GPGRT_ENABLE_ES_MACROS: Define to provide "es_" macros for the
estream functions.
In addition to the error codes, Libgpg-error also provides a set of
functions used by most GnuPG components. */
/* The error source type gpg_err_source_t.
Where as the Poo out of a welle small
Taketh his firste springing and his sours.
--Chaucer. */
/* Only use free slots, never change or reorder the existing
entries. */
typedef enum
{
@include:err-sources@
/* This is one more than the largest allowed entry. */
GPG_ERR_SOURCE_DIM = 128
} gpg_err_source_t;
/* The error code type gpg_err_code_t. */
/* Only use free slots, never change or reorder the existing
entries. */
typedef enum
{
@include:err-codes@
/* The following error codes are used to map system errors. */
#define GPG_ERR_SYSTEM_ERROR (1 << 15)
@include:errnos@
/* This is one more than the largest allowed entry. */
GPG_ERR_CODE_DIM = 65536
} gpg_err_code_t;
/* The error value type gpg_error_t. */
/* We would really like to use bit-fields in a struct, but using
structs as return values can cause binary compatibility issues, in
particular if you want to do it effeciently (also see
-freg-struct-return option to GCC). */
typedef unsigned int gpg_error_t;
/* We use the lowest 16 bits of gpg_error_t for error codes. The 16th
bit indicates system errors. */
#define GPG_ERR_CODE_MASK (GPG_ERR_CODE_DIM - 1)
/* Bits 17 to 24 are reserved. */
/* We use the upper 7 bits of gpg_error_t for error sources. */
#define GPG_ERR_SOURCE_MASK (GPG_ERR_SOURCE_DIM - 1)
#define GPG_ERR_SOURCE_SHIFT 24
/* The highest bit is reserved. It shouldn't be used to prevent
potential negative numbers when transmitting error values as
text. */
/* GCC feature test. */
#if __GNUC__
# define _GPG_ERR_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#else
# define _GPG_ERR_GCC_VERSION 0
#endif
#undef _GPG_ERR_HAVE_CONSTRUCTOR
#if _GPG_ERR_GCC_VERSION > 30100
# define _GPG_ERR_CONSTRUCTOR __attribute__ ((__constructor__))
# define _GPG_ERR_HAVE_CONSTRUCTOR
#else
# define _GPG_ERR_CONSTRUCTOR
#endif
#if _GPG_ERR_GCC_VERSION >= 40400
# define _GPGRT_GCC_A_PRINTF(f, a) __attribute__ ((format(__gnu_printf__,f,a)))
#elif _GPG_ERR_GCC_VERSION >= 20500
# define _GPGRT_GCC_A_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
#else
# define _GPGRT_GCC_A_PRINTF(f, a)
#endif
#if _GPG_ERR_GCC_VERSION >= 29200
# define _GPGRT__RESTRICT __restrict__
#else
# define _GPGRT__RESTRICT
#endif
/* Initialization function. */
/* Initialize the library. This function should be run early. */
gpg_error_t gpg_err_init (void) _GPG_ERR_CONSTRUCTOR;
/* If this is defined, the library is already initialized by the
constructor and does not need to be initialized explicitely. */
#undef GPG_ERR_INITIALIZED
#ifdef _GPG_ERR_HAVE_CONSTRUCTOR
# define GPG_ERR_INITIALIZED 1
# define gpgrt_init() do { gpg_err_init (); } while (0)
#else
# define gpgrt_init() do { ; } while (0)
#endif
-/* Register blocking system I/O clamping functions. */
-void gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void));
-
/* See the source on how to use the deinit function; it is usually not
required. */
void gpg_err_deinit (int mode);
+/* Register blocking system I/O clamping functions. */
+void gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void));
+
+/* Register a custom malloc/realloc/free function. */
+void gpgrt_set_alloc_func (void *(*f)(void *a, size_t n));
+
+
/* Constructor and accessor functions. */
/* Construct an error value from an error code and source. Within a
subsystem, use gpg_error. */
static GPG_ERR_INLINE gpg_error_t
gpg_err_make (gpg_err_source_t source, gpg_err_code_t code)
{
return code == GPG_ERR_NO_ERROR ? GPG_ERR_NO_ERROR
: (((source & GPG_ERR_SOURCE_MASK) << GPG_ERR_SOURCE_SHIFT)
| (code & GPG_ERR_CODE_MASK));
}
/* The user should define GPG_ERR_SOURCE_DEFAULT before including this
file to specify a default source for gpg_error. */
#ifndef GPG_ERR_SOURCE_DEFAULT
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_UNKNOWN
#endif
static GPG_ERR_INLINE gpg_error_t
gpg_error (gpg_err_code_t code)
{
return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, code);
}
/* Retrieve the error code from an error value. */
static GPG_ERR_INLINE gpg_err_code_t
gpg_err_code (gpg_error_t err)
{
return (gpg_err_code_t) (err & GPG_ERR_CODE_MASK);
}
/* Retrieve the error source from an error value. */
static GPG_ERR_INLINE gpg_err_source_t
gpg_err_source (gpg_error_t err)
{
return (gpg_err_source_t) ((err >> GPG_ERR_SOURCE_SHIFT)
& GPG_ERR_SOURCE_MASK);
}
/* String functions. */
/* Return a pointer to a string containing a description of the error
code in the error value ERR. This function is not thread-safe. */
const char *gpg_strerror (gpg_error_t err);
/* Return the error string for ERR in the user-supplied buffer BUF of
size BUFLEN. This function is, in contrast to gpg_strerror,
thread-safe if a thread-safe strerror_r() function is provided by
the system. If the function succeeds, 0 is returned and BUF
contains the string describing the error. If the buffer was not
large enough, ERANGE is returned and BUF contains as much of the
beginning of the error string as fits into the buffer. */
int gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen);
/* Return a pointer to a string containing a description of the error
source in the error value ERR. */
const char *gpg_strsource (gpg_error_t err);
/* Mapping of system errors (errno). */
/* Retrieve the error code for the system error ERR. This returns
GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
this). */
gpg_err_code_t gpg_err_code_from_errno (int err);
/* Retrieve the system error for the error code CODE. This returns 0
if CODE is not a system error code. */
int gpg_err_code_to_errno (gpg_err_code_t code);
/* Retrieve the error code directly from the ERRNO variable. This
returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
(report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
gpg_err_code_t gpg_err_code_from_syserror (void);
/* Set the ERRNO variable. This function is the preferred way to set
ERRNO due to peculiarities on WindowsCE. */
void gpg_err_set_errno (int err);
/* Return or check the version. Both functions are identical. */
const char *gpgrt_check_version (const char *req_version);
const char *gpg_error_check_version (const char *req_version);
/* The version string of this header. */
#define GPG_ERROR_VERSION @version@
/* The version number of this header. */
#define GPG_ERROR_VERSION_NUMBER @version-number@
@include:os-add@
/* Self-documenting convenience functions. */
static GPG_ERR_INLINE gpg_error_t
gpg_err_make_from_errno (gpg_err_source_t source, int err)
{
return gpg_err_make (source, gpg_err_code_from_errno (err));
}
static GPG_ERR_INLINE gpg_error_t
gpg_error_from_errno (int err)
{
return gpg_error (gpg_err_code_from_errno (err));
}
static GPG_ERR_INLINE gpg_error_t
gpg_error_from_syserror (void)
{
return gpg_error (gpg_err_code_from_syserror ());
}
/* Lock functions. */
@include:lock-obj@
#define GPGRT_LOCK_DEFINE(name) \
static gpgrt_lock_t name = GPGRT_LOCK_INITIALIZER
/* NB: If GPGRT_LOCK_DEFINE is not used, zero out the lock variable
before passing it to gpgrt_lock_init. */
gpg_err_code_t gpgrt_lock_init (gpgrt_lock_t *lockhd);
gpg_err_code_t gpgrt_lock_lock (gpgrt_lock_t *lockhd);
gpg_err_code_t gpgrt_lock_trylock (gpgrt_lock_t *lockhd);
gpg_err_code_t gpgrt_lock_unlock (gpgrt_lock_t *lockhd);
gpg_err_code_t gpgrt_lock_destroy (gpgrt_lock_t *lockhd);
/* Thread functions. */
gpg_err_code_t gpgrt_yield (void);
/* Estream */
/* 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 _gpgrt_stream_internal;
struct _gpgrt__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. */
/* Various flags. */
struct {
unsigned int magic: 16;
unsigned int writing: 1;
unsigned int reserved: 15;
} flags;
/* 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;
/* A pointer to our internal data for this stream. */
struct _gpgrt_stream_internal *intern;
};
/* The opaque type for an estream. */
typedef struct _gpgrt__stream *gpgrt_stream_t;
#ifdef GPGRT_ENABLE_ES_MACROS
typedef struct _gpgrt__stream *estream_t;
#endif
typedef ssize_t (*gpgrt_cookie_read_function_t) (void *cookie,
void *buffer, size_t size);
typedef ssize_t (*gpgrt_cookie_write_function_t) (void *cookie,
const void *buffer,
size_t size);
typedef int (*gpgrt_cookie_seek_function_t) (void *cookie,
off_t *pos, int whence);
typedef int (*gpgrt_cookie_close_function_t) (void *cookie);
struct _gpgrt_cookie_io_functions
{
gpgrt_cookie_read_function_t func_read;
gpgrt_cookie_write_function_t func_write;
gpgrt_cookie_seek_function_t func_seek;
gpgrt_cookie_close_function_t func_close;
};
typedef struct _gpgrt_cookie_io_functions gpgrt_cookie_io_functions_t;
#ifdef GPGRT_ENABLE_ES_MACROS
typedef struct _gpgrt_cookie_io_functions es_cookie_io_functions_t;
#define es_cookie_read_function_t gpgrt_cookie_read_function_t
#define es_cookie_write_function_t gpgrt_cookie_read_function_t
#define es_cookie_seek_function_t gpgrt_cookie_read_function_t
#define es_cookie_close_function_t gpgrt_cookie_read_function_t
#endif
enum gpgrt_syshd_types
{
GPGRT_SYSHD_NONE = 0, /* No system handle available. */
GPGRT_SYSHD_FD = 1, /* A file descriptor as returned by open(). */
GPGRT_SYSHD_SOCK = 2, /* A socket as returned by socket(). */
GPGRT_SYSHD_RVID = 3, /* A rendevous id (see libassuan's gpgcedev.c). */
GPGRT_SYSHD_HANDLE = 4 /* A HANDLE object (Windows). */
};
struct _gpgrt_syshd
{
enum gpgrt_syshd_types type;
union {
int fd;
int sock;
int rvid;
void *handle;
} u;
};
typedef struct _gpgrt_syshd gpgrt_syshd_t;
#ifdef GPGRT_ENABLE_ES_MACROS
typedef struct _gpgrt_syshd es_syshd_t;
#define ES_SYSHD_NONE GPGRT_SYSHD_NONE
#define ES_SYSHD_FD GPGRT_SYSHD_FD
#define ES_SYSHD_SOCK GPGRT_SYSHD_SOCK
#define ES_SYSHD_RVID GPGRT_SYSHD_RVID
#define ES_SYSHD_HANDLE GPGRT_SYSHD_HANDLE
#endif
gpgrt_stream_t gpgrt_fopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode);
gpgrt_stream_t gpgrt_mopen (void *_GPGRT__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 *_GPGRT__RESTRICT mode);
gpgrt_stream_t gpgrt_fopenmem (size_t memlimit,
const char *_GPGRT__RESTRICT mode);
gpgrt_stream_t gpgrt_fopenmem_init (size_t memlimit,
const char *_GPGRT__RESTRICT mode,
const void *data, size_t datalen);
gpgrt_stream_t gpgrt_fdopen (int filedes, const char *mode);
gpgrt_stream_t gpgrt_fdopen_nc (int filedes, const char *mode);
gpgrt_stream_t gpgrt_sysopen (gpgrt_syshd_t *syshd, const char *mode);
gpgrt_stream_t gpgrt_sysopen_nc (gpgrt_syshd_t *syshd, const char *mode);
gpgrt_stream_t gpgrt_fpopen (FILE *fp, const char *mode);
gpgrt_stream_t gpgrt_fpopen_nc (FILE *fp, const char *mode);
gpgrt_stream_t gpgrt_freopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode,
gpgrt_stream_t _GPGRT__RESTRICT stream);
gpgrt_stream_t gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
const char *_GPGRT__RESTRICT mode,
gpgrt_cookie_io_functions_t functions);
int gpgrt_fclose (gpgrt_stream_t stream);
int gpgrt_fclose_snatch (gpgrt_stream_t stream,
void **r_buffer, size_t *r_buflen);
int gpgrt_onclose (gpgrt_stream_t stream, int mode,
void (*fnc) (gpgrt_stream_t, void*), void *fnc_value);
int gpgrt_fileno (gpgrt_stream_t stream);
int gpgrt_fileno_unlocked (gpgrt_stream_t stream);
int gpgrt_syshd (gpgrt_stream_t stream, gpgrt_syshd_t *syshd);
int gpgrt_syshd_unlocked (gpgrt_stream_t stream, gpgrt_syshd_t *syshd);
void _gpgrt_set_std_fd (int no, int fd);
gpgrt_stream_t _gpgrt_get_std_stream (int fd);
#define gpgrt_stdin _gpgrt_get_std_stream (0)
#define gpgrt_stdout _gpgrt_get_std_stream (1)
#define gpgrt_stderr _gpgrt_get_std_stream (2)
void gpgrt_flockfile (gpgrt_stream_t stream);
int gpgrt_ftrylockfile (gpgrt_stream_t stream);
void gpgrt_funlockfile (gpgrt_stream_t stream);
int gpgrt_feof (gpgrt_stream_t stream);
int gpgrt_feof_unlocked (gpgrt_stream_t stream);
int gpgrt_ferror (gpgrt_stream_t stream);
int gpgrt_ferror_unlocked (gpgrt_stream_t stream);
void gpgrt_clearerr (gpgrt_stream_t stream);
void gpgrt_clearerr_unlocked (gpgrt_stream_t stream);
int gpgrt_fflush (gpgrt_stream_t stream);
int gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence);
int gpgrt_fseeko (gpgrt_stream_t stream, off_t offset, int whence);
long int gpgrt_ftell (gpgrt_stream_t stream);
off_t gpgrt_ftello (gpgrt_stream_t stream);
void gpgrt_rewind (gpgrt_stream_t stream);
int gpgrt_fgetc (gpgrt_stream_t stream);
int gpgrt_fputc (int c, gpgrt_stream_t stream);
int _gpgrt_getc_underflow (gpgrt_stream_t stream);
int _gpgrt_putc_overflow (int c, gpgrt_stream_t stream);
#define gpgrt_getc_unlocked(stream) \
(((!(stream)->flags.writing) \
&& ((stream)->data_offset < (stream)->data_len) \
&& (! (stream)->unread_data_len)) \
? ((int) (stream)->buffer[((stream)->data_offset)++]) \
: _gpgrt_getc_underflow ((stream)))
#define gpgrt_putc_unlocked(c, stream) \
(((stream)->flags.writing \
&& ((stream)->data_offset < (stream)->buffer_size) \
&& (c != '\n')) \
? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \
: _gpgrt_putc_overflow ((c), (stream)))
#define gpgrt_getc(stream) gpgrt_fgetc (stream)
#define gpgrt_putc(c, stream) gpgrt_fputc (c, stream)
int gpgrt_ungetc (int c, gpgrt_stream_t stream);
int gpgrt_read (gpgrt_stream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT buffer, size_t bytes_to_read,
size_t *_GPGRT__RESTRICT bytes_read);
int gpgrt_write (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write,
size_t *_GPGRT__RESTRICT bytes_written);
int gpgrt_write_sanitized (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
const char *delimiters,
size_t *_GPGRT__RESTRICT bytes_written);
int gpgrt_write_hexstring (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
int reserved,
size_t *_GPGRT__RESTRICT bytes_written);
size_t gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
gpgrt_stream_t _GPGRT__RESTRICT stream);
size_t gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t memb,
gpgrt_stream_t _GPGRT__RESTRICT stream);
char *gpgrt_fgets (char *_GPGRT__RESTRICT s, int n,
gpgrt_stream_t _GPGRT__RESTRICT stream);
int gpgrt_fputs (const char *_GPGRT__RESTRICT s,
gpgrt_stream_t _GPGRT__RESTRICT stream);
int gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s,
gpgrt_stream_t _GPGRT__RESTRICT stream);
ssize_t gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr,
size_t *_GPGRT__RESTRICT n,
gpgrt_stream_t stream);
ssize_t gpgrt_read_line (gpgrt_stream_t stream,
char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length);
void gpgrt_free (void *a);
int gpgrt_fprintf (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(2,3);
int gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(2,3);
int gpgrt_printf (const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(1,2);
int gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(1,2);
int gpgrt_vfprintf (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, va_list ap)
_GPGRT_GCC_A_PRINTF(2,0);
int gpgrt_vfprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, va_list ap)
_GPGRT_GCC_A_PRINTF(2,0);
int gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream,
char *_GPGRT__RESTRICT buf, int mode, size_t size);
void gpgrt_setbuf (gpgrt_stream_t _GPGRT__RESTRICT stream,
char *_GPGRT__RESTRICT buf);
void gpgrt_set_binary (gpgrt_stream_t stream);
gpgrt_stream_t gpgrt_tmpfile (void);
void gpgrt_opaque_set (gpgrt_stream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT opaque);
void *gpgrt_opaque_get (gpgrt_stream_t stream);
void gpgrt_fname_set (gpgrt_stream_t stream, const char *fname);
const char *gpgrt_fname_get (gpgrt_stream_t stream);
int gpgrt_asprintf (char **r_buf, const char * _GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(2,3);
int gpgrt_vasprintf (char **r_buf, const char * _GPGRT__RESTRICT format,
va_list ap)
_GPGRT_GCC_A_PRINTF(2,0);
char *gpgrt_bsprintf (const char * _GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(1,2);
char *gpgrt_vbsprintf (const char * _GPGRT__RESTRICT format, va_list ap)
_GPGRT_GCC_A_PRINTF(1,0);
int gpgrt_snprintf (char *buf, size_t bufsize,
const char * _GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(3,4);
int gpgrt_vsnprintf (char *buf,size_t bufsize,
const char * _GPGRT__RESTRICT format, va_list arg_ptr)
_GPGRT_GCC_A_PRINTF(3,0);
#ifdef GPGRT_ENABLE_ES_MACROS
# define es_fopen gpgrt_fopen
# define es_mopen gpgrt_mopen
# define es_fopenmem gpgrt_fopenmem
# define es_fopenmem_init gpgrt_fopenmem_init
# define es_fdopen gpgrt_fdopen
# define es_fdopen_nc gpgrt_fdopen_nc
# define es_sysopen gpgrt_sysopen
# define es_sysopen_nc gpgrt_sysopen_nc
# define es_fpopen gpgrt_fpopen
# define es_fpopen_nc gpgrt_fpopen_nc
# define es_freopen gpgrt_freopen
# define es_fopencookie gpgrt_fopencookie
# define es_fclose gpgrt_fclose
# define es_fclose_snatch gpgrt_fclose_snatch
# define es_onclose gpgrt_onclose
# define es_fileno gpgrt_fileno
# define es_fileno_unlocked gpgrt_fileno_unlocked
# define es_syshd gpgrt_syshd
# define es_syshd_unlocked gpgrt_syshd_unlocked
# define es_stdin _gpgrt_get_std_stream (0)
# define es_stdout _gpgrt_get_std_stream (1)
# define es_stderr _gpgrt_get_std_stream (2)
# define es_flockfile gpgrt_flockfile
# define es_ftrylockfile gpgrt_ftrylockfile
# define es_funlockfile gpgrt_funlockfile
# define es_feof gpgrt_feof
# define es_feof_unlocked gpgrt_feof_unlocked
# define es_ferror gpgrt_ferror
# define es_ferror_unlocked gpgrt_ferror_unlocked
# define es_clearerr gpgrt_clearerr
# define es_clearerr_unlocked gpgrt_clearerr_unlocked
# define es_fflush gpgrt_fflush
# define es_fseek gpgrt_fseek
# define es_fseeko gpgrt_fseeko
# define es_ftell gpgrt_ftell
# define es_ftello gpgrt_ftello
# define es_rewind gpgrt_rewind
# define es_fgetc gpgrt_fgetc
# define es_fputc gpgrt_fputc
# define es_getc_unlocked gpgrt_getc_unlocked
# define es_putc_unlocked gpgrt_putc_unlocked
# define es_getc gpgrt_getc
# define es_putc gpgrt_putc
# define es_ungetc gpgrt_ungetc
# define es_read gpgrt_read
# define es_write gpgrt_write
# define es_write_sanitized gpgrt_write_sanitized
# define es_write_hexstring gpgrt_write_hexstring
# define es_fread gpgrt_fread
# define es_fwrite gpgrt_fwrite
# define es_fgets gpgrt_fgets
# define es_fputs gpgrt_fputs
# define es_fputs_unlocked gpgrt_fputs_unlocked
# define es_getline gpgrt_getline
# define es_read_line gpgrt_read_line
# define es_free gpgrt_free
# define es_fprintf gpgrt_fprintf
# define es_fprintf_unlocked gpgrt_fprintf_unlocked
# define es_printf gpgrt_printf
# define es_printf_unlocked gpgrt_printf_unlocked
# define es_vfprintf gpgrt_vfprintf
# define es_vfprintf_unlocked gpgrt_vfprintf_unlocked
# define es_setvbuf gpgrt_setvbuf
# define es_setbuf gpgrt_setbuf
# define es_set_binary gpgrt_set_binary
# define es_tmpfile gpgrt_tmpfile
# define es_opaque_set gpgrt_opaque_set
# define es_opaque_get gpgrt_opaque_get
# define es_fname_set gpgrt_fname_set
# define es_fname_get gpgrt_fname_get
# define es_asprintf gpgrt_asprintf
# define es_vasprintf gpgrt_vasprintf
# define es_bsprintf gpgrt_bsprintf
# define es_vbsprintf gpgrt_vbsprintf
#endif /*GPGRT_ENABLE_ES_MACROS*/
#ifdef __cplusplus
}
#endif
#endif /* GPG_ERROR_H */
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index 0847cfe..43becea 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -1,124 +1,125 @@
# libgpg-error.vers - What symbols to export -*- std -*-
# Copyright (C) 2014 g10 Code GmbH
#
# This file is part of libgpg-error.
#
# libgpg-error 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.
#
# libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
#
# NOTE: When adding new functions, please make sure to add them to
# visibility.h and gpg-error.def.in as well.
GPG_ERROR_1.0 {
global:
gpg_strerror;
gpg_strerror_r;
gpg_strsource;
gpg_err_code_from_errno;
gpg_err_code_to_errno;
gpg_err_code_from_syserror;
gpg_err_set_errno;
gpg_error_check_version;
gpgrt_lock_init;
gpgrt_lock_lock;
gpgrt_lock_unlock;
gpgrt_lock_destroy;
gpgrt_yield;
gpgrt_lock_trylock;
gpgrt_set_syscall_clamp;
gpgrt_fopen;
gpgrt_mopen;
gpgrt_fopenmem;
gpgrt_fopenmem_init;
gpgrt_fdopen;
gpgrt_fdopen_nc;
gpgrt_sysopen;
gpgrt_sysopen_nc;
gpgrt_fpopen;
gpgrt_fpopen_nc;
gpgrt_freopen;
gpgrt_fopencookie;
gpgrt_fclose;
gpgrt_fclose_snatch;
gpgrt_onclose;
gpgrt_fileno;
gpgrt_fileno_unlocked;
gpgrt_syshd;
gpgrt_syshd_unlocked;
_gpgrt_set_std_fd;
_gpgrt_get_std_stream;
gpgrt_flockfile;
gpgrt_ftrylockfile;
gpgrt_funlockfile;
gpgrt_feof;
gpgrt_feof_unlocked;
gpgrt_ferror;
gpgrt_ferror_unlocked;
gpgrt_clearerr;
gpgrt_clearerr_unlocked;
gpgrt_fflush;
gpgrt_fseek;
gpgrt_fseeko;
gpgrt_ftell;
gpgrt_ftello;
gpgrt_rewind;
gpgrt_fgetc;
_gpgrt_getc_underflow;
gpgrt_fputc;
_gpgrt_putc_overflow;
gpgrt_ungetc;
gpgrt_read;
gpgrt_write;
gpgrt_write_sanitized;
gpgrt_write_hexstring;
gpgrt_fread;
gpgrt_fwrite;
gpgrt_fgets;
gpgrt_fputs;
gpgrt_fputs_unlocked;
gpgrt_getline;
gpgrt_read_line;
gpgrt_free;
gpgrt_fprintf;
gpgrt_fprintf_unlocked;
gpgrt_printf;
gpgrt_printf_unlocked;
gpgrt_vfprintf;
gpgrt_vfprintf_unlocked;
gpgrt_setvbuf;
gpgrt_setbuf;
gpgrt_set_binary;
gpgrt_tmpfile;
gpgrt_opaque_set;
gpgrt_opaque_get;
gpgrt_fname_set;
gpgrt_fname_get;
gpgrt_asprintf;
gpgrt_vasprintf;
gpgrt_bsprintf;
gpgrt_vbsprintf;
gpgrt_snprintf;
gpgrt_vsnprintf;
gpgrt_check_version;
gpg_err_init;
gpg_err_deinit;
+ gpgrt_set_alloc_func;
local:
*;
};
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index a029ac0..df7c606 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -1,198 +1,203 @@
/* gpgrt-int.h - Internal definitions
* Copyright (C) 2014 g10 Code GmbH
*
* This file is part of libgpg-error.
*
* libgpg-error 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.
*
* libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GPGRT_GPGRT_INT_H
#define _GPGRT_GPGRT_INT_H
#include "gpg-error.h"
#include "visibility.h"
/* Local error function prototypes. */
const char *_gpg_strerror (gpg_error_t err);
int _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen);
const char *_gpg_strsource (gpg_error_t err);
gpg_err_code_t _gpg_err_code_from_errno (int err);
int _gpg_err_code_to_errno (gpg_err_code_t code);
gpg_err_code_t _gpg_err_code_from_syserror (void);
void _gpg_err_set_errno (int err);
gpg_error_t _gpg_err_init (void);
void _gpg_err_deinit (int mode);
+void _gpgrt_set_alloc_func (void *(*f)(void *a, size_t n));
+
+void *_gpgrt_realloc (void *a, size_t n);
+void *_gpgrt_malloc (size_t n);
+void _gpgrt_free (void *a);
+
const char *_gpg_error_check_version (const char *req_version);
gpg_err_code_t _gpgrt_lock_init (gpgrt_lock_t *lockhd);
gpg_err_code_t _gpgrt_lock_lock (gpgrt_lock_t *lockhd);
gpg_err_code_t _gpgrt_lock_trylock (gpgrt_lock_t *lockhd);
gpg_err_code_t _gpgrt_lock_unlock (gpgrt_lock_t *lockhd);
gpg_err_code_t _gpgrt_lock_destroy (gpgrt_lock_t *lockhd);
gpg_err_code_t _gpgrt_yield (void);
/* Local prototypes for estream. */
int _gpgrt_es_init (void);
void _gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void));
gpgrt_stream_t _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode);
gpgrt_stream_t _gpgrt_mopen (void *_GPGRT__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 *_GPGRT__RESTRICT mode);
gpgrt_stream_t _gpgrt_fopenmem (size_t memlimit,
const char *_GPGRT__RESTRICT mode);
gpgrt_stream_t _gpgrt_fopenmem_init (size_t memlimit,
const char *_GPGRT__RESTRICT mode,
const void *data, size_t datalen);
gpgrt_stream_t _gpgrt_fdopen (int filedes, const char *mode);
gpgrt_stream_t _gpgrt_fdopen_nc (int filedes, const char *mode);
gpgrt_stream_t _gpgrt_sysopen (gpgrt_syshd_t *syshd, const char *mode);
gpgrt_stream_t _gpgrt_sysopen_nc (gpgrt_syshd_t *syshd, const char *mode);
gpgrt_stream_t _gpgrt_fpopen (FILE *fp, const char *mode);
gpgrt_stream_t _gpgrt_fpopen_nc (FILE *fp, const char *mode);
gpgrt_stream_t _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode,
gpgrt_stream_t _GPGRT__RESTRICT stream);
gpgrt_stream_t _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
const char *_GPGRT__RESTRICT mode,
gpgrt_cookie_io_functions_t functions);
int _gpgrt_fclose (gpgrt_stream_t stream);
int _gpgrt_fclose_snatch (gpgrt_stream_t stream,
void **r_buffer, size_t *r_buflen);
int _gpgrt_onclose (gpgrt_stream_t stream, int mode,
void (*fnc) (gpgrt_stream_t, void*), void *fnc_value);
int _gpgrt_fileno (gpgrt_stream_t stream);
int _gpgrt_fileno_unlocked (gpgrt_stream_t stream);
int _gpgrt_syshd (gpgrt_stream_t stream, gpgrt_syshd_t *syshd);
int _gpgrt_syshd_unlocked (gpgrt_stream_t stream, gpgrt_syshd_t *syshd);
void _gpgrt__set_std_fd (int no, int fd);
gpgrt_stream_t _gpgrt__get_std_stream (int fd);
void _gpgrt_flockfile (gpgrt_stream_t stream);
int _gpgrt_ftrylockfile (gpgrt_stream_t stream);
void _gpgrt_funlockfile (gpgrt_stream_t stream);
int _gpgrt_feof (gpgrt_stream_t stream);
int _gpgrt_feof_unlocked (gpgrt_stream_t stream);
int _gpgrt_ferror (gpgrt_stream_t stream);
int _gpgrt_ferror_unlocked (gpgrt_stream_t stream);
void _gpgrt_clearerr (gpgrt_stream_t stream);
void _gpgrt_clearerr_unlocked (gpgrt_stream_t stream);
int _gpgrt_fflush (gpgrt_stream_t stream);
int _gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence);
int _gpgrt_fseeko (gpgrt_stream_t stream, off_t offset, int whence);
long int _gpgrt_ftell (gpgrt_stream_t stream);
off_t _gpgrt_ftello (gpgrt_stream_t stream);
void _gpgrt_rewind (gpgrt_stream_t stream);
int _gpgrt_fgetc (gpgrt_stream_t stream);
int _gpgrt_fputc (int c, gpgrt_stream_t stream);
int _gpgrt__getc_underflow (gpgrt_stream_t stream);
int _gpgrt__putc_overflow (int c, gpgrt_stream_t stream);
/* Note: Keeps the next two macros in sync
with their counterparts in gpg-error.h. */
#define _gpgrt_getc_unlocked(stream) \
(((!(stream)->flags.writing) \
&& ((stream)->data_offset < (stream)->data_len) \
&& (! (stream)->unread_data_len)) \
? ((int) (stream)->buffer[((stream)->data_offset)++]) \
: _gpgrt__getc_underflow ((stream)))
#define _gpgrt_putc_unlocked(c, stream) \
(((stream)->flags.writing \
&& ((stream)->data_offset < (stream)->buffer_size) \
&& (c != '\n')) \
? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \
: _gpgrt__putc_overflow ((c), (stream)))
int _gpgrt_ungetc (int c, gpgrt_stream_t stream);
int _gpgrt_read (gpgrt_stream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT buffer, size_t bytes_to_read,
size_t *_GPGRT__RESTRICT bytes_read);
int _gpgrt_write (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write,
size_t *_GPGRT__RESTRICT bytes_written);
int _gpgrt_write_sanitized (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
const char *delimiters,
size_t *_GPGRT__RESTRICT bytes_written);
int _gpgrt_write_hexstring (gpgrt_stream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
int reserved,
size_t *_GPGRT__RESTRICT bytes_written);
size_t _gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
gpgrt_stream_t _GPGRT__RESTRICT stream);
size_t _gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr,
size_t size, size_t memb,
gpgrt_stream_t _GPGRT__RESTRICT stream);
char *_gpgrt_fgets (char *_GPGRT__RESTRICT s, int n,
gpgrt_stream_t _GPGRT__RESTRICT stream);
int _gpgrt_fputs (const char *_GPGRT__RESTRICT s,
gpgrt_stream_t _GPGRT__RESTRICT stream);
int _gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s,
gpgrt_stream_t _GPGRT__RESTRICT stream);
ssize_t _gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr,
size_t *_GPGRT__RESTRICT n,
gpgrt_stream_t stream);
ssize_t _gpgrt_read_line (gpgrt_stream_t stream,
char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length);
-void _gpgrt_free (void *a);
int _gpgrt_fprintf (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(2,3);
int _gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
_GPGRT_GCC_A_PRINTF(2,3);
int _gpgrt_vfprintf (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, va_list ap)
_GPGRT_GCC_A_PRINTF(2,0);
int _gpgrt_vfprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, va_list ap)
_GPGRT_GCC_A_PRINTF(2,0);
int _gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream,
char *_GPGRT__RESTRICT buf, int mode, size_t size);
void _gpgrt_set_binary (gpgrt_stream_t stream);
gpgrt_stream_t _gpgrt_tmpfile (void);
void _gpgrt_opaque_set (gpgrt_stream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT opaque);
void *_gpgrt_opaque_get (gpgrt_stream_t stream);
void _gpgrt_fname_set (gpgrt_stream_t stream, const char *fname);
const char *_gpgrt_fname_get (gpgrt_stream_t stream);
#include "estream-printf.h"
#endif /*_GPGRT_GPGRT_INT_H*/
diff --git a/src/init.c b/src/init.c
index 16cdfed..6305fe3 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1,437 +1,494 @@
/* init.c - Initialize the GnuPG error library.
Copyright (C) 2005, 2010 g10 Code GmbH
This file is part of libgpg-error.
libgpg-error 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.
libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "gpgrt-int.h"
#include "gettext.h"
#include "init.h"
#ifdef HAVE_W32CE_SYSTEM
# include "mkw32errmap.map.c" /* Generated map_w32codes () */
# ifndef TLS_OUT_OF_INDEXES
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
# endif
# ifndef __MINGW32CE__
# /* Replace the Mingw32CE provided abort function. */
# define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0)
# endif
#endif
/* Locale directory support. */
#if HAVE_W32_SYSTEM
#include <windows.h>
static int tls_index = TLS_OUT_OF_INDEXES; /* Index for the TLS functions. */
static char *get_locale_dir (void);
static void drop_locale_dir (char *locale_dir);
#else /*!HAVE_W32_SYSTEM*/
#define get_locale_dir() LOCALEDIR
#define drop_locale_dir(dir)
#endif /*!HAVE_W32_SYSTEM*/
+
+/* The realloc function as set by gpgrt_set_alloc_func. */
+static void *(*custom_realloc)(void *a, size_t n);
+
+
static void
real_init (void)
{
#ifdef ENABLE_NLS
char *locale_dir;
/* We only have to bind our locale directory to our text domain. */
locale_dir = get_locale_dir ();
if (locale_dir)
{
bindtextdomain (PACKAGE, locale_dir);
drop_locale_dir (locale_dir);
}
#endif
_gpgrt_es_init ();
}
/* Initialize the library. This function should be run early. */
gpg_error_t
_gpg_err_init (void)
{
#ifdef HAVE_W32_SYSTEM
# ifdef DLL_EXPORT
/* We always have a constructor and thus this function is called
automatically. Due to the way the C init code of mingw works,
the constructors are called before our DllMain function is
called. The problem with that is that the TLS has not been setup
and w32-gettext.c requires TLS. To solve this we do nothing here
but call the actual init code from our DllMain. */
# else /*!DLL_EXPORT*/
/* Note that if the TLS is actually used, we can't release the TLS
as there is no way to know when a thread terminates (i.e. no
thread-specific-atexit). You are really better off to use the
DLL! */
if (tls_index == TLS_OUT_OF_INDEXES)
{
tls_index = TlsAlloc ();
if (tls_index == TLS_OUT_OF_INDEXES)
{
/* No way to continue - commit suicide. */
abort ();
}
_gpg_w32__init_gettext_module ();
real_init ();
}
# endif /*!DLL_EXPORT*/
#else
real_init ();
#endif
return 0;
}
/* Deinitialize libgpg-error. This function is only used in special
circumstances. No gpg-error function should be used after this
function has been called. A value of 0 passed for MODE
deinitializes the entire libgpg-error, a value of 1 releases
resources allocated for the current thread and only that thread may
not anymore access libgpg-error after such a call. Under Windows
this function may be called from the DllMain function of a DLL
which statically links to libgpg-error. */
void
_gpg_err_deinit (int mode)
{
#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
struct tls_space_s *tls;
tls = TlsGetValue (tls_index);
if (tls)
{
TlsSetValue (tls_index, NULL);
LocalFree (tls);
}
if (mode == 0)
{
TlsFree (tls_index);
tls_index = TLS_OUT_OF_INDEXES;
}
#else
(void)mode;
#endif
}
+
+
+/* Register F as allocation function. This function is used for all
+ APIs which return an allocated buffer. F needs to have standard
+ realloc semantics. It should be called as early as possible and
+ not changed later. */
+void
+_gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
+{
+ custom_realloc = f;
+}
+
+
+/* The realloc to be used for data returned by the public API. */
+void *
+_gpgrt_realloc (void *a, size_t n)
+{
+ if (custom_realloc)
+ return custom_realloc (a, n);
+
+ if (!a)
+ return malloc (n);
+
+ if (!n)
+ {
+ free (a);
+ return NULL;
+ }
+
+ return realloc (a, n);
+}
+
+
+/* The malloc to be used for data returned by the public API. */
+void *
+_gpgrt_malloc (size_t n)
+{
+ if (!n)
+ n++;
+ return _gpgrt_realloc (NULL, n);
+}
+
+
+/* The free to be used for data returned by the public API. */
+void
+_gpgrt_free (void *a)
+{
+ _gpgrt_realloc (a, 0);
+}
+
+
+
#ifdef HAVE_W32_SYSTEM
/* Return a malloced string encoded in UTF-8 from the wide char input
string STRING. Caller must free this value. Returns NULL on
failure. Caller may use GetLastError to get the actual error
number. The result of calling this function with STRING set to
NULL is not defined. */
static char *
wchar_to_utf8 (const wchar_t *string)
{
int n;
char *result;
/* Note, that CP_UTF8 is not defined in Windows versions earlier
than NT. */
n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
if (n < 0)
return NULL;
result = malloc (n+1);
if (result)
{
n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
if (n < 0)
{
free (result);
result = NULL;
}
}
return result;
}
/* Return a malloced wide char string from an UTF-8 encoded input
string STRING. Caller must free this value. Returns NULL on
failure. Caller may use GetLastError to get the actual error
number. The result of calling this function with STRING set to
NULL is not defined. */
static wchar_t *
utf8_to_wchar (const char *string)
{
int n;
wchar_t *result;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
if (n < 0)
return NULL;
result = malloc ((n+1) * sizeof *result);
if (result)
{
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
if (n < 0)
{
free (result);
result = NULL;
}
return NULL;
}
return result;
}
static char *
get_locale_dir (void)
{
static wchar_t moddir[MAX_PATH+5];
char *result, *p;
int nbytes;
if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
*moddir = 0;
#define SLDIR "\\share\\locale"
if (*moddir)
{
nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
if (nbytes < 0)
return NULL;
result = malloc (nbytes + strlen (SLDIR) + 1);
if (result)
{
nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
result, nbytes, NULL, NULL);
if (nbytes < 0)
{
free (result);
result = NULL;
}
else
{
p = strrchr (result, '\\');
if (p)
*p = 0;
/* If we are installed below "bin" strip that part and
use the top directory instead.
Background: Under Windows we don't install GnuPG
below bin/ but in the top directory with only share/,
lib/, and etc/ below it. One of the reasons is to
keep the the length of the filenames at bay so not to
increase the limited length of the PATH envvar.
Another and more important reason, however, is that
the very first GPG versions on W32 were installed
into a flat directory structure and for best
compatibility with these versions we didn't changed
that later. For WindowsCE we can right away install
it under bin, though. The hack with detection of the
bin directory part allows us to eventually migrate to
such a directory layout under plain Windows without
the need to change libgpg-error. */
p = strrchr (result, '\\');
if (p && !strcmp (p+1, "bin"))
*p = 0;
/* Append the static part. */
strcat (result, SLDIR);
}
}
}
else /* Use the old default value. */
{
result = malloc (10 + strlen (SLDIR) + 1);
if (result)
{
strcpy (result, "c:\\gnupg");
strcat (result, SLDIR);
}
}
#undef SLDIR
return result;
}
static void
drop_locale_dir (char *locale_dir)
{
free (locale_dir);
}
/* Return the tls object. This function is guaranteed to return a
valid non-NULL object. */
struct tls_space_s *
get_tls (void)
{
struct tls_space_s *tls;
tls = TlsGetValue (tls_index);
if (!tls)
{
/* Called by a thread which existed before this DLL was loaded.
Allocate the space. */
tls = LocalAlloc (LPTR, sizeof *tls);
if (!tls)
{
/* No way to continue - commit suicide. */
abort ();
}
tls->gt_use_utf8 = 0;
TlsSetValue (tls_index, tls);
}
return tls;
}
/* Return the value of the ERRNO variable. This needs to be a
function so that we can have a per-thread ERRNO. This is used only
on WindowsCE because that OS misses an errno. */
#ifdef HAVE_W32CE_SYSTEM
int
_gpg_w32ce_get_errno (void)
{
return map_w32codes ( GetLastError () );
}
#endif /*HAVE_W32CE_SYSTEM*/
/* Replacement strerror function for WindowsCE. */
#ifdef HAVE_W32CE_SYSTEM
char *
_gpg_w32ce_strerror (int err)
{
struct tls_space_s *tls = get_tls ();
wchar_t tmpbuf[STRBUFFER_SIZE];
int n;
if (err == -1)
err = _gpg_w32ce_get_errno ();
/* Note: On a German HTC Touch Pro2 device I also tried
LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
English messages. */
if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
tmpbuf, STRBUFFER_SIZE -1,
NULL))
{
n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
tls->strerror_buffer,
sizeof tls->strerror_buffer -1,
NULL, NULL);
}
else
n = -1;
if (n < 0)
snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
"[w32err=%d]", err);
return tls->strerror_buffer;
}
#endif /*HAVE_W32CE_SYSTEM*/
void
_gpg_err_set_errno (int err)
{
#ifdef HAVE_W32CE_SYSTEM
SetLastError (err);
#else /*!HAVE_W32CE_SYSTEM*/
errno = err;
#endif /*!HAVE_W32CE_SYSTEM*/
}
/* Entry point called by the DLL loader. */
#ifdef DLL_EXPORT
int WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
struct tls_space_s *tls;
(void)reserved;
(void)hinst;
switch (reason)
{
case DLL_PROCESS_ATTACH:
tls_index = TlsAlloc ();
if (tls_index == TLS_OUT_OF_INDEXES)
return FALSE;
#ifndef _GPG_ERR_HAVE_CONSTRUCTOR
/* If we have not constructors (e.g. MSC) we call it here. */
_gpg_w32__init_gettext_module ();
#endif
/* falltru. */
case DLL_THREAD_ATTACH:
tls = LocalAlloc (LPTR, sizeof *tls);
if (!tls)
return FALSE;
tls->gt_use_utf8 = 0;
TlsSetValue (tls_index, tls);
if (reason == DLL_PROCESS_ATTACH)
{
real_init ();
}
break;
case DLL_THREAD_DETACH:
tls = TlsGetValue (tls_index);
if (tls)
LocalFree (tls);
break;
case DLL_PROCESS_DETACH:
tls = TlsGetValue (tls_index);
if (tls)
LocalFree (tls);
TlsFree (tls_index);
break;
default:
break;
}
return TRUE;
}
#endif /*DLL_EXPORT*/
#else /*!HAVE_W32_SYSTEM*/
void
_gpg_err_set_errno (int err)
{
errno = err;
}
#endif /*!HAVE_W32_SYSTEM*/
diff --git a/src/visibility.c b/src/visibility.c
index 829c720..f1bbca6 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1,671 +1,677 @@
/* visibility.c - Wrapper for all public functions.
* Copyright (C) 2014 g10 Code GmbH
*
* This file is part of libgpg-error.
*
* libgpg-error 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.
*
* libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdarg.h>
#define _GPGRT_INCL_BY_VISIBILITY_C 1
#include "gpgrt-int.h"
const char *
gpg_strerror (gpg_error_t err)
{
return _gpg_strerror (err);
}
int
gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen)
{
return _gpg_strerror_r (err, buf, buflen);
}
const char *
gpg_strsource (gpg_error_t err)
{
return _gpg_strsource (err);
}
gpg_err_code_t
gpg_err_code_from_errno (int err)
{
return _gpg_err_code_from_errno (err);
}
int
gpg_err_code_to_errno (gpg_err_code_t code)
{
return _gpg_err_code_to_errno (code);
}
gpg_err_code_t
gpg_err_code_from_syserror (void)
{
return _gpg_err_code_from_syserror ();
}
void
gpg_err_set_errno (int err)
{
_gpg_err_set_errno (err);
}
gpg_error_t
gpg_err_init (void)
{
return _gpg_err_init ();
}
void
gpg_err_deinit (int mode)
{
_gpg_err_deinit (mode);
}
const char *
gpg_error_check_version (const char *req_version)
{
return _gpg_error_check_version (req_version);
}
const char *
gpgrt_check_version (const char *req_version)
{
return _gpg_error_check_version (req_version);
}
void
gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void))
{
_gpgrt_set_syscall_clamp (pre, post);
}
+void
+gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
+{
+ _gpgrt_set_alloc_func (f);
+}
+
gpg_err_code_t
gpgrt_lock_init (gpgrt_lock_t *lockhd)
{
return _gpgrt_lock_init (lockhd);
}
gpg_err_code_t
gpgrt_lock_lock (gpgrt_lock_t *lockhd)
{
return _gpgrt_lock_lock (lockhd);
}
gpg_err_code_t
gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
{
return _gpgrt_lock_trylock (lockhd);
}
gpg_err_code_t
gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
{
return _gpgrt_lock_unlock (lockhd);
}
gpg_err_code_t
gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
{
return _gpgrt_lock_destroy (lockhd);
}
gpg_err_code_t
gpgrt_yield (void)
{
return _gpgrt_yield ();
}
estream_t
gpgrt_fopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode)
{
return _gpgrt_fopen (path, mode);
}
estream_t
gpgrt_mopen (void *_GPGRT__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 *_GPGRT__RESTRICT mode)
{
return _gpgrt_mopen (data, data_n, data_len, grow, func_realloc, func_free,
mode);
}
estream_t
gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
{
return _gpgrt_fopenmem (memlimit, mode);
}
estream_t
gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode,
const void *data, size_t datalen)
{
return _gpgrt_fopenmem_init (memlimit, mode, data, datalen);
}
estream_t
gpgrt_fdopen (int filedes, const char *mode)
{
return _gpgrt_fdopen (filedes, mode);
}
estream_t
gpgrt_fdopen_nc (int filedes, const char *mode)
{
return _gpgrt_fdopen_nc (filedes, mode);
}
estream_t
gpgrt_sysopen (es_syshd_t *syshd, const char *mode)
{
return _gpgrt_sysopen (syshd, mode);
}
estream_t
gpgrt_sysopen_nc (es_syshd_t *syshd, const char *mode)
{
return _gpgrt_sysopen_nc (syshd, mode);
}
estream_t
gpgrt_fpopen (FILE *fp, const char *mode)
{
return _gpgrt_fpopen (fp, mode);
}
estream_t
gpgrt_fpopen_nc (FILE *fp, const char *mode)
{
return _gpgrt_fpopen_nc (fp, mode);
}
estream_t
gpgrt_freopen (const char *_GPGRT__RESTRICT path,
const char *_GPGRT__RESTRICT mode,
estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_freopen (path, mode, stream);
}
estream_t
gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
const char *_GPGRT__RESTRICT mode,
gpgrt_cookie_io_functions_t functions)
{
return _gpgrt_fopencookie (cookie, mode, functions);
}
int
gpgrt_fclose (estream_t stream)
{
return _gpgrt_fclose (stream);
}
int
gpgrt_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen)
{
return _gpgrt_fclose_snatch (stream, r_buffer, r_buflen);
}
int
gpgrt_onclose (estream_t stream, int mode,
void (*fnc) (estream_t, void*), void *fnc_value)
{
return _gpgrt_onclose (stream, mode, fnc, fnc_value);
}
int
gpgrt_fileno (estream_t stream)
{
return _gpgrt_fileno (stream);
}
int
gpgrt_fileno_unlocked (estream_t stream)
{
return _gpgrt_fileno_unlocked (stream);
}
int
gpgrt_syshd (estream_t stream, es_syshd_t *syshd)
{
return _gpgrt_syshd (stream, syshd);
}
int
gpgrt_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
{
return _gpgrt_syshd_unlocked (stream, syshd);
}
void
_gpgrt_set_std_fd (int no, int fd)
{
_gpgrt__set_std_fd (no, fd); /* (double dash in name) */
}
estream_t
_gpgrt_get_std_stream (int fd)
{
return _gpgrt__get_std_stream (fd); /* (double dash in name) */
}
void
gpgrt_flockfile (estream_t stream)
{
_gpgrt_flockfile (stream);
}
int
gpgrt_ftrylockfile (estream_t stream)
{
return _gpgrt_ftrylockfile (stream);
}
void
gpgrt_funlockfile (estream_t stream)
{
_gpgrt_funlockfile (stream);
}
int
gpgrt_feof (estream_t stream)
{
return _gpgrt_feof (stream);
}
int
gpgrt_feof_unlocked (estream_t stream)
{
return _gpgrt_feof_unlocked (stream);
}
int
gpgrt_ferror (estream_t stream)
{
return _gpgrt_ferror (stream);
}
int
gpgrt_ferror_unlocked (estream_t stream)
{
return _gpgrt_ferror_unlocked (stream);
}
void
gpgrt_clearerr (estream_t stream)
{
_gpgrt_clearerr (stream);
}
void
gpgrt_clearerr_unlocked (estream_t stream)
{
_gpgrt_clearerr_unlocked (stream);
}
int
gpgrt_fflush (estream_t stream)
{
return _gpgrt_fflush (stream);
}
int
gpgrt_fseek (estream_t stream, long int offset, int whence)
{
return _gpgrt_fseek (stream, offset, whence);
}
int
gpgrt_fseeko (estream_t stream, off_t offset, int whence)
{
return _gpgrt_fseeko (stream, offset, whence);
}
long int
gpgrt_ftell (estream_t stream)
{
return _gpgrt_ftell (stream);
}
off_t
gpgrt_ftello (estream_t stream)
{
return _gpgrt_ftello (stream);
}
void
gpgrt_rewind (estream_t stream)
{
_gpgrt_rewind (stream);
}
int
gpgrt_fgetc (estream_t stream)
{
return _gpgrt_fgetc (stream);
}
int
_gpgrt_getc_underflow (estream_t stream)
{
return _gpgrt__getc_underflow (stream);
}
int
gpgrt_fputc (int c, estream_t stream)
{
return _gpgrt_fputc (c, stream);
}
int
_gpgrt_putc_overflow (int c, estream_t stream)
{
return _gpgrt__putc_overflow (c, stream);
}
int
gpgrt_ungetc (int c, estream_t stream)
{
return _gpgrt_ungetc (c, stream);
}
int
gpgrt_read (estream_t _GPGRT__RESTRICT stream,
void *_GPGRT__RESTRICT buffer, size_t bytes_to_read,
size_t *_GPGRT__RESTRICT bytes_read)
{
return _gpgrt_read (stream, buffer, bytes_to_read, bytes_read);
}
int
gpgrt_write (estream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write,
size_t *_GPGRT__RESTRICT bytes_written)
{
return _gpgrt_write (stream, buffer, bytes_to_write, bytes_written);
}
int
gpgrt_write_sanitized (estream_t _GPGRT__RESTRICT stream,
const void * _GPGRT__RESTRICT buffer, size_t length,
const char * delimiters,
size_t * _GPGRT__RESTRICT bytes_written)
{
return _gpgrt_write_sanitized (stream, buffer, length, delimiters,
bytes_written);
}
int
gpgrt_write_hexstring (estream_t _GPGRT__RESTRICT stream,
const void *_GPGRT__RESTRICT buffer, size_t length,
int reserved, size_t *_GPGRT__RESTRICT bytes_written )
{
return _gpgrt_write_hexstring (stream, buffer, length, reserved,
bytes_written);
}
size_t
gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_fread (ptr, size, nitems, stream);
}
size_t
gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_fwrite (ptr, size, nitems, stream);
}
char *
gpgrt_fgets (char *_GPGRT__RESTRICT buffer, int length,
estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_fgets (buffer, length, stream);
}
int
gpgrt_fputs (const char *_GPGRT__RESTRICT s, estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_fputs (s, stream);
}
int
gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s,
estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_fputs_unlocked (s, stream);
}
ssize_t
gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr,
size_t *_GPGRT__RESTRICT n, estream_t _GPGRT__RESTRICT stream)
{
return _gpgrt_getline (lineptr, n, stream);
}
ssize_t
gpgrt_read_line (estream_t stream,
char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length)
{
return _gpgrt_read_line (stream, addr_of_buffer, length_of_buffer,
max_length);
}
void
gpgrt_free (void *a)
{
if (a)
_gpgrt_free (a);
}
int
gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format,
va_list ap)
{
return _gpgrt_vfprintf (stream, format, ap);
}
int
gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format,
va_list ap)
{
return _gpgrt_vfprintf_unlocked (stream, format, ap);
}
int
gpgrt_printf (const char *_GPGRT__RESTRICT format, ...)
{
va_list ap;
int rc;
va_start (ap, format);
rc = _gpgrt_vfprintf (es_stdout, format, ap);
va_end (ap);
return rc;
}
int
gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...)
{
va_list ap;
int rc;
va_start (ap, format);
rc = _gpgrt_vfprintf_unlocked (es_stdout, format, ap);
va_end (ap);
return rc;
}
int
gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
{
va_list ap;
int rc;
va_start (ap, format);
rc = _gpgrt_vfprintf (stream, format, ap);
va_end (ap);
return rc;
}
int
gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
const char *_GPGRT__RESTRICT format, ...)
{
va_list ap;
int rc;
va_start (ap, format);
rc = _gpgrt_vfprintf_unlocked (stream, format, ap);
va_end (ap);
return rc;
}
int
gpgrt_setvbuf (estream_t _GPGRT__RESTRICT stream,
char *_GPGRT__RESTRICT buf, int type, size_t size)
{
return _gpgrt_setvbuf (stream, buf, type, size);
}
void
gpgrt_setbuf (estream_t _GPGRT__RESTRICT stream, char *_GPGRT__RESTRICT buf)
{
_gpgrt_setvbuf (stream, buf, buf? _IOFBF : _IONBF, BUFSIZ);
}
void
gpgrt_set_binary (estream_t stream)
{
_gpgrt_set_binary (stream);
}
estream_t
gpgrt_tmpfile (void)
{
return _gpgrt_tmpfile ();
}
void
gpgrt_opaque_set (estream_t stream, void *opaque)
{
_gpgrt_opaque_set (stream, opaque);
}
void *
gpgrt_opaque_get (estream_t stream)
{
return _gpgrt_opaque_get (stream);
}
void
gpgrt_fname_set (estream_t stream, const char *fname)
{
_gpgrt_fname_set (stream, fname);
}
const char *
gpgrt_fname_get (estream_t stream)
{
return _gpgrt_fname_get (stream);
}
int
gpgrt_asprintf (char **r_buf, const char *_GPGRT__RESTRICT format, ...)
{
va_list ap;
int rc;
va_start (ap, format);
rc = _gpgrt_estream_vasprintf (r_buf, format, ap);
va_end (ap);
return rc;
}
int
gpgrt_vasprintf (char **r_buf, const char *_GPGRT__RESTRICT format, va_list ap)
{
return _gpgrt_estream_vasprintf (r_buf, format, ap);
}
char *
gpgrt_bsprintf (const char *_GPGRT__RESTRICT format, ...)
{
int rc;
va_list ap;
char *buf;
va_start (ap, format);
rc = _gpgrt_estream_vasprintf (&buf, format, ap);
va_end (ap);
if (rc < 0)
return NULL;
return buf;
}
char *
gpgrt_vbsprintf (const char *_GPGRT__RESTRICT format, va_list ap)
{
int rc;
char *buf;
rc = _gpgrt_estream_vasprintf (&buf, format, ap);
if (rc < 0)
return NULL;
return buf;
}
int
gpgrt_snprintf (char *buf, size_t bufsize, const char *format, ...)
{
int rc;
va_list arg_ptr;
va_start (arg_ptr, format);
rc = _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr);
va_end (arg_ptr);
return rc;
}
int
gpgrt_vsnprintf (char *buf, size_t bufsize,
const char *format, va_list arg_ptr)
{
return _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr);
}
diff --git a/src/visibility.h b/src/visibility.h
index d0ef0bf..feeb8d1 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -1,243 +1,249 @@
/* visibility.h - Set visibility attribute
* Copyright (C) 2014 g10 Code GmbH
*
* This file is part of libgpg-error.
*
* libgpg-error 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.
*
* libgpg-error 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 this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GPGRT_VISIBILITY_H
#define _GPGRT_VISIBILITY_H
/* Include the main header here so that public symbols are mapped to
the internal underscored ones. */
#ifdef _GPGRT_INCL_BY_VISIBILITY_C
# include "gpgrt-int.h"
#endif
/* Our use of the ELF visibility feature works by passing
-fvisibiliy=hidden on the command line and by explicitly marking
all exported functions as visible.
NOTE: When adding new functions, please make sure to add them to
gpg-error.vers and gpg-error.def.in as well. */
#ifdef _GPGRT_INCL_BY_VISIBILITY_C
# ifdef GPGRT_USE_VISIBILITY
# define MARK_VISIBLE(name) \
extern __typeof__ (name) name __attribute__ ((visibility("default")));
# else
# define MARK_VISIBLE(name) /* */
# endif
MARK_VISIBLE (gpg_strerror)
MARK_VISIBLE (gpg_strerror_r)
MARK_VISIBLE (gpg_strsource)
MARK_VISIBLE (gpg_err_code_from_errno)
MARK_VISIBLE (gpg_err_code_to_errno)
MARK_VISIBLE (gpg_err_code_from_syserror)
MARK_VISIBLE (gpg_err_set_errno)
MARK_VISIBLE (gpg_err_init)
+MARK_VISIBLE (gpg_err_deinit)
MARK_VISIBLE (gpg_error_check_version)
MARK_VISIBLE (gpgrt_check_version)
MARK_VISIBLE (gpgrt_lock_init)
MARK_VISIBLE (gpgrt_lock_lock)
MARK_VISIBLE (gpgrt_lock_unlock)
MARK_VISIBLE (gpgrt_lock_destroy)
MARK_VISIBLE (gpgrt_yield)
MARK_VISIBLE (gpgrt_lock_trylock)
MARK_VISIBLE (gpgrt_fopen)
MARK_VISIBLE (gpgrt_mopen)
MARK_VISIBLE (gpgrt_fopenmem)
MARK_VISIBLE (gpgrt_fopenmem_init)
MARK_VISIBLE (gpgrt_fdopen)
MARK_VISIBLE (gpgrt_fdopen_nc)
MARK_VISIBLE (gpgrt_sysopen)
MARK_VISIBLE (gpgrt_sysopen_nc)
MARK_VISIBLE (gpgrt_fpopen)
MARK_VISIBLE (gpgrt_fpopen_nc)
MARK_VISIBLE (gpgrt_freopen)
MARK_VISIBLE (gpgrt_fopencookie)
MARK_VISIBLE (gpgrt_fclose)
MARK_VISIBLE (gpgrt_fclose_snatch)
MARK_VISIBLE (gpgrt_onclose)
MARK_VISIBLE (gpgrt_fileno)
MARK_VISIBLE (gpgrt_fileno_unlocked)
MARK_VISIBLE (gpgrt_syshd)
MARK_VISIBLE (gpgrt_syshd_unlocked)
MARK_VISIBLE (_gpgrt_set_std_fd)
MARK_VISIBLE (_gpgrt_get_std_stream)
MARK_VISIBLE (gpgrt_flockfile)
MARK_VISIBLE (gpgrt_ftrylockfile)
MARK_VISIBLE (gpgrt_funlockfile)
MARK_VISIBLE (gpgrt_feof)
MARK_VISIBLE (gpgrt_feof_unlocked)
MARK_VISIBLE (gpgrt_ferror)
MARK_VISIBLE (gpgrt_ferror_unlocked)
MARK_VISIBLE (gpgrt_clearerr)
MARK_VISIBLE (gpgrt_clearerr_unlocked)
MARK_VISIBLE (gpgrt_fflush)
MARK_VISIBLE (gpgrt_fseek)
MARK_VISIBLE (gpgrt_fseeko)
MARK_VISIBLE (gpgrt_ftell)
MARK_VISIBLE (gpgrt_ftello)
MARK_VISIBLE (gpgrt_rewind)
MARK_VISIBLE (gpgrt_fgetc)
MARK_VISIBLE (_gpgrt_getc_underflow)
MARK_VISIBLE (gpgrt_fputc)
MARK_VISIBLE (_gpgrt_putc_overflow)
MARK_VISIBLE (gpgrt_ungetc)
MARK_VISIBLE (gpgrt_read)
MARK_VISIBLE (gpgrt_write)
MARK_VISIBLE (gpgrt_write_sanitized)
MARK_VISIBLE (gpgrt_write_hexstring)
MARK_VISIBLE (gpgrt_fread)
MARK_VISIBLE (gpgrt_fwrite)
MARK_VISIBLE (gpgrt_fgets)
MARK_VISIBLE (gpgrt_fputs)
MARK_VISIBLE (gpgrt_fputs_unlocked)
MARK_VISIBLE (gpgrt_getline)
MARK_VISIBLE (gpgrt_read_line)
MARK_VISIBLE (gpgrt_free)
MARK_VISIBLE (gpgrt_fprintf)
MARK_VISIBLE (gpgrt_fprintf_unlocked)
MARK_VISIBLE (gpgrt_printf)
MARK_VISIBLE (gpgrt_printf_unlocked)
MARK_VISIBLE (gpgrt_vfprintf)
MARK_VISIBLE (gpgrt_vfprintf_unlocked)
MARK_VISIBLE (gpgrt_setvbuf)
MARK_VISIBLE (gpgrt_setbuf)
MARK_VISIBLE (gpgrt_set_binary)
MARK_VISIBLE (gpgrt_tmpfile)
MARK_VISIBLE (gpgrt_opaque_set)
MARK_VISIBLE (gpgrt_opaque_get)
MARK_VISIBLE (gpgrt_fname_set)
MARK_VISIBLE (gpgrt_fname_get)
MARK_VISIBLE (gpgrt_asprintf)
MARK_VISIBLE (gpgrt_vasprintf)
MARK_VISIBLE (gpgrt_bsprintf)
MARK_VISIBLE (gpgrt_vbsprintf)
MARK_VISIBLE (gpgrt_snprintf)
MARK_VISIBLE (gpgrt_vsnprintf)
MARK_VISIBLE (gpgrt_set_syscall_clamp)
+MARK_VISIBLE (gpgrt_set_alloc_func)
#undef MARK_VISIBLE
#else /*!_GPGRT_INCL_BY_VISIBILITY_C*/
/* To avoid accidental use of the public functions inside Libgpg-error,
we redefine them to catch such errors. */
#define gpg_strerror _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_strerror_r _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_strsource _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_err_code_from_errno _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_err_code_to_errno _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_err_code_from_syserror _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_err_set_errno _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_err_init _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpg_err_deinit _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpg_error_check_version _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_check_version _gpgrt_USE_OTHER_FUNCTION
-#define gpgrt_set_syscall_clamp _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_lock_init _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_lock_lock _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_lock_unlock _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_lock_destroy _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_yield _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_lock_trylock _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_mopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fopenmem _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fopenmem_init _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fdopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fdopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_sysopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_sysopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fpopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fpopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_freopen _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fopencookie _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fclose _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fclose_snatch _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_onclose _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fileno _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fileno_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_syshd _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_syshd_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define _gpgrt_set_std_fd _gpgrt_USE_UNDERSCORED_FUNCTION
#define _gpgrt_get_std_stream _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_flockfile _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_ftrylockfile _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_funlockfile _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_feof _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_feof_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_ferror _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_ferror_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_clearerr _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_clearerr_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fflush _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fseek _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fseeko _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_ftell _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_ftello _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_rewind _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fgetc _gpgrt_USE_UNDERSCORED_FUNCTION
#define _gpgrt_getc_underflow _gpgrt_USE_DBLUNDERSCO_FUNCTION
#define gpgrt_fputc _gpgrt_USE_UNDERSCORED_FUNCTION
#define _gpgrt_putc_overflow _gpgrt_USE_DBLUNDERSCO_FUNCTION
#define gpgrt_ungetc _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_read _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_write _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_write_sanitized _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_write_hexstring _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fread _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fwrite _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fgets _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fputs _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fputs_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_getline _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_read_line _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_free _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fprintf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_printf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_printf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_vfprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_vfprintf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_setvbuf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_setbuf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_set_binary _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_tmpfile _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_opaque_set _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_opaque_get _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fname_set _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_fname_get _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_asprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_vasprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_bsprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_vbsprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_snprintf _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_vsnprintf _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_syscall_clamp _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_alloc_func _gpgrt_USE_UNDERSCORED_FUNCTION
+
+
#endif /*!_GPGRT_INCL_BY_VISIBILITY_C*/
#endif /*_GPGRT_VISIBILITY_H*/

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 1, 10:27 PM (1 d, 28 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
4e/24/3250d838761d8115e8e370fc136d

Event Timeline