[libgetdata] 04/08: New upstream 0.9.3

Alastair McKinstry mckinstry at moszumanska.debian.org
Wed May 3 10:35:11 UTC 2017


This is an automated email from the git hooks/post-receive script.

mckinstry pushed a commit to tag debian/0.9.3-1
in repository libgetdata.

commit a5eb00218197a81944e2383580d5148387f41c5f
Author: Alastair McKinstry <mckinstry at debian.org>
Date:   Wed Aug 3 12:23:32 2016 +0100

    New upstream 0.9.3
---
 AUTHORS                                        |    2 +-
 ChangeLog                                      |  309 +++++++
 Makefile.am                                    |    9 +-
 Makefile.in                                    |   12 +-
 NEWS                                           |  120 ++-
 aclocal.m4                                     |    2 +-
 bindings/Makefile.am                           |    4 +-
 bindings/Makefile.in                           |    6 +-
 bindings/cxx/Makefile.am                       |    3 +-
 bindings/cxx/Makefile.in                       |    5 +-
 bindings/cxx/getdata/dirfile.h                 |   21 +-
 bindings/cxx/getdata/entry.h                   |   45 +-
 bindings/cxx/getdata/fragment.h                |   19 +-
 bindings/cxx/getdata/types.h                   |  102 +++
 bindings/cxx/internal.h                        |   27 +
 bindings/cxx/test/Makefile.in                  |    2 +
 bindings/f77/Makefile.in                       |    2 +
 bindings/f77/test/Makefile.in                  |    2 +
 bindings/idl/Makefile.am                       |    4 +-
 bindings/idl/Makefile.in                       |    6 +-
 bindings/idl/makedlm.sh.in                     |    6 +-
 bindings/idl/test/Makefile.in                  |    2 +
 bindings/make_parameters.c                     |   11 +-
 bindings/matlab/Makefile.am                    |    4 +-
 bindings/matlab/Makefile.in                    |    6 +-
 bindings/matlab/getdata_constants.m            |    2 +-
 bindings/matlab/make_contents.sh.in            |   10 +-
 bindings/matlab/test/Makefile.in               |    2 +
 bindings/matlab/test/test.sh                   |    2 +-
 bindings/perl/Makefile.am                      |    2 +-
 bindings/perl/Makefile.in                      |    4 +-
 bindings/php/Makefile.in                       |    2 +
 bindings/php/getdata.c                         | 1004 +++++++++++++----------
 bindings/php/php_getdata.h                     |   17 +-
 bindings/php/test/Makefile.in                  |    2 +
 bindings/php/test/callback.php                 |    5 +-
 bindings/python/Makefile.am                    |   17 +-
 bindings/python/Makefile.in                    |   64 +-
 bindings/python/{pygetdata.h => gdpy_intern.h} |  126 ++-
 bindings/python/pydirfile.c                    | 1019 ++++++++++++++++--------
 bindings/python/pyentry.c                      |  905 +++++++++++++--------
 bindings/python/pyfragment.c                   |   97 ++-
 bindings/python/pygetdata.c                    |  850 +++++++++++++++-----
 bindings/python/pygetdata.h                    |  141 +---
 bindings/python/test/Makefile.am               |    2 +-
 bindings/python/test/Makefile.in               |    4 +-
 bindings/python/test/big_test.py               |  245 +++---
 bindings/python/test/callback.py               |   28 +-
 bindings/python/test/char_enc1.py              |  245 ++++++
 bindings/python/test/char_enc2.py              |  242 ++++++
 bindings/python/test/char_enc3.py              |  366 +++++++++
 configure                                      |  844 +++++++++++++++-----
 configure.ac                                   |   67 +-
 doc/Makefile.in                                |    2 +
 m4/compiler.m4                                 |   10 +-
 m4/encoding.m4                                 |   20 +-
 m4/idl.m4                                      |   64 +-
 m4/matlab.m4                                   |   11 +-
 m4/perl.m4                                     |   36 +-
 m4/php.m4                                      |   27 +-
 m4/python.m4                                   |  178 ++++-
 m4/version.m4                                  |    8 +-
 m4/win32.m4                                    |    4 +-
 man/Makefile.in                                |    2 +
 man/dirfile-format.5                           |    8 +-
 man/gd_carrays.3                               |   11 +-
 man/gd_verbose_prefix.3                        |   14 +-
 src/Makefile.am                                |    4 +-
 src/Makefile.in                                |    9 +-
 src/common.c                                   |   12 +-
 src/gd_config.h.in                             |   12 +
 test/del_bad_code.c => src/gd_extra_config.h   |   40 +-
 src/getdata.h.in                               |    2 +-
 src/globals.c                                  |    6 -
 src/include.c                                  |    4 +
 src/internal.h                                 |    2 +-
 src/name.c                                     |   22 +-
 src/parse.c                                    |    8 +-
 src/sie.c                                      |   84 +-
 test/Makefile.am                               |   37 +-
 test/Makefile.in                               |  519 ++++++------
 test/del_bad_code.c                            |    2 +-
 test/{del_bad_code.c => get_linterp_nodir.c}   |   35 +-
 test/{del_bad_code.c => sie_get_header.c}      |   40 +-
 test/sie_put_header.c                          |   87 ++
 util/Makefile.in                               |    2 +
 86 files changed, 5956 insertions(+), 2411 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 6787106..b93e9c6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -17,7 +17,7 @@ library.
 Joseph Fowler <jfowler at princeton.edu> provided code which was adapted to
 create the slimlib encoding support.
 
-Adam D Hincks <adam.hincks at utoronto.ca> provided code whic was adapted to
+Adam D Hincks <adam.hincks at utoronto.ca> provided code which was adapted to
 create the zzip encoding support.  The original zzip encoding (ZIRFILE) was
 developed by Mike Nolta <nolta at cita.utoronto.ca>.
 
diff --git a/ChangeLog b/ChangeLog
index d65b8fc..dff2016 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,312 @@
+2016-07-20   D. V. Wiebe <getdata at ketiltrout.net> svn:1091
+	GetData-0.9.3 released.
+
+2016-06-28   D. V. Wiebe <getdata at ketiltrout.net> svn:1088
+	* bindings/php/php_getdata.h: Handle zend_register_long_constant() call
+	changes in PHP7.
+
+2016-06-28   D. V. Wiebe <getdata at ketiltrout.net> svn:1087
+	* src/sie.c (_GD_SampIndSeek): Check fread return value.
+
+2016-06-28   D. V. Wiebe <getdata at ketiltrout.net> svn:1086
+	* src/sie.c (_GD_SampIndDiscardHeader): Added.
+	* src/sie.c (_GD_SampIndDoOpen): Call _GD_SampIndDiscardHeader to look for
+	(and skip) the header.
+	* src/sie.c (_GD_SampIndSeek): Seek past the header on rewind.
+	* test/sie_get_header.c test/sie_put_header.c: Added.
+
+2016-06-23   D. V. Wiebe <getdata at ketiltrout.net> svn:1085
+	* bindings/make_parameters.c (PHP): in constants.c, use the macro
+	GDPHP_REGISTER_LONG_CONSTANT instead of zend_register_long_constant
+	directly.
+
+	* bindings/php/getdata.c: There's a large section at the top abstracting
+	PHP5 and PHP7.
+
+	* bindings/php/getdata.c (gdphp_add_assoc_complex gdphp_add_assoc_cmparray
+	gdphp_data_to_array gd_carrays gd_mcarrays): In PHP7, allocate a zval on the
+	stack to pass to gdphp_from_complex because it can't allocate one anymore.
+
+	* bindings/php/getdata.c (gd_getdata): Free data on error.
+
+	* bindings/php/getdata.c (gd_madd_bit gd_madd_sbit): Correctly deal with
+	NULL numbits.
+
+2016-05-25   D. V. Wiebe <getdata at ketiltrout.net> svn:1082
+	* bindings/python/gdpy_intern.h: Renamed from pygd_intern.h
+
+2016-05-25   D. V. Wiebe <getdata at ketiltrout.net> svn:1080,1081
+	* bindings/idl/Makefile.am: Remove -p from mkdir call
+
+	* bindings/idl/makedlm.sh.in bindings/matlab/Makefile.am
+	bindings/matlab/make_contents.sh.in m4/idl.m4 (GD_IDL_VAR
+	GD_IDL_CHECK_VERSION GD_IDL): Use "grep" instead of "${GREP}"
+	* configure.ac bindings/idl/package/configure.ac
+	bindings/matlab/package/configure.ac: Remove AC_PROG_GREP call:
+	baseline grep should be sufficient for us, whatever it is.
+	* bindings/matlab/make_contents.sh.in: use "grep | head" instead of
+	"grep -m"
+	* m4/compiler.m4 (GD_LANG_F77_COMPILER_INTEL GD_LANG_FC_COMPILER_INTEL)
+	m4/idl.m4 (GD_IDL_CHECK_VERSION GD_IDL) m4/matlab.m4 (GD_MATLAB):
+	Redirect grep output to /dev/null instead of using "grep -q"
+
+	* bindings/matlab/make_contents.sh.in bindings/matlab/test/test.sh: Use
+	expr instead of basename
+
+	* bindings/matlab/make_contents.sh.in: Use tr instead of ${AWK}
+
+	* bindings/idl/package/configure.ac bindings/matlab/package/configure.ac:
+	Remove AC_PROG_SED call: baseline sed should be sufficient for us,
+	whatever it is.
+	* configure.ac: Don't make Fortran or Perl bindings if we don't have ${SED}:
+	baseline sed isn't necessarily good enough.
+	* m4/idl.m4 (GD_IDL_CHECK_VERSION GD_IDL) bindings/matlab/Makefile.am: Use
+	sed instead of ${SED}
+
+	* bindings/idl/makedlm.sh.in: set LC_ALL=C
+
+	* m4/win32.m4 (GD_MSYS_SHELL): Use ${AWK} instead of "grep | awk"
+
+2016-05-20   D. V. Wiebe <getdata at ketiltrout.net> svn:1078
+	* configure.ac: Require SED and GREP to build the IDL bindings.
+	* m4/idl.m4 (GD_IDL): Define and AC_SUBST idl_prefix.  Replace idl_prefix
+	with exec_prefix in idldir if needed.
+	* m4/idl.m4 (GD_IDL_VAR): Added.
+
+	* m4/perl.m4 (GD_PERL) m4/php.m4 (GD_PHP): Replace the interpreter's prefix
+	with ${exec_prefix} in install directories if possible.
+
+	* m4/python.m4 (GD_PYTHON): Fix pythondir calculation to use exec_prefix.
+	And also PYTHON_LDVERSION instead of PYTHON_VERSION.
+
+	* Makefile.am bindings/idl/package/Makefile.am: remove all the directory
+	options from DISTCHECK_CONFIGURE_FLAGS.
+
+	* bindings/idl/package/configure.ac: Abort if GREP and SED aren't defined.
+
+2016-05-19   D. V. Wiebe <getdata at ketiltrout.net> svn:1075
+	* bindings/cxx/getdata/types.h: Added.
+	* bindings/cxx/getdata/dirfile.h: include getdata/types.h instead of
+	getdata.h directly.
+	* bindings/cxx/getdata/entry.h: include getdata/types.h instead of
+	getdata/dirfile.h.  DataType, EntryType, WindOpType moved to
+	getdata/types.h.
+	* bindings/cxx/getdata/fragment.h: include getdata/types.h instead of
+	getdata/dirfile.h.  EncodingScheme moved to getdata/types.h
+
+	* bindings/cxx/internal.h: Include everything explicitly to avoid
+	accidentally including a file outside the source tree instead.
+
+2016-05-12   D. V. Wiebe <getdata at ketiltrout.net> svn:1073
+	* bindings/python/pygd_intern.h: Don't include numpy/arrayobject.h unless
+	GDPY_INCLUDE_NUMPY id defined.
+	* bindings/python/pygetdata.c bindings/python/pydirfile.c: Define
+	GDPY_INCLUDE_NUMPY.
+
+	* bindings/python/pydirfile.c (gdpy_dirfile_setreference
+	gdpy_dirfile_setstandards gdpy_dirfile_setmplexlookback)
+	bindings/python/pyentry.c (gdpy_entry_setname gdpy_entry_setfragment
+	gdpy_entry_setinfields gdpy_entry_setdatatype gdpy_entry_setarraylen
+	gdpy_entry_setnfields gdpy_entry_setm gdpy_entry_setb gdpy_entry_settable
+	gdpy_entry_setdividend gdpy_entry_seta gdpy_entry_setpolyord
+	gdpy_entry_setparms gdpy_entry_setwindop): Prohibit deletion.
+	* bindings/python/pydirfile.c (gdpy_dirfile_getflags): Zero flags on delete.
+	* bindings/python/pydirfile.c (gdpy_dirfile_setverboseprefix): Set prefix to
+	NULL on delete.
+	* bindings/python/pyentry.c (gdpy_entry_getnumbits): Set numbits to 1 on
+	delete.
+	* bindings/python/pyentry.c (gdpy_entry_setperiod): Set period to 0 on
+	delete.
+	* bindings/python/pyfragment.c (gdpy_fragment_setprotection): Set to
+	GD_PROTECT_NONE on delete.
+	* bindings/python/pyfragment.c (gdpy_fragment_setprefix
+	gdpy_fragment_setsuffix): Set to parent's affix on delete.
+	* bindings/python/pyentry.c (gdpy_set_scalar_from_pyobj): Handle pyobj =
+	NULL (i.e. attribute deletion).
+	* bindings/python/pygetdata.c (gdpy_parse_charenc): Handle value == NULL. 
+
+	* configure.ac: Look for PyErr_NewExceptionWithDoc.
+	* m4/python.m4 (GD_PYTHON): Compute PYTHON_LDFLAGS for configure's use.
+	* bindings/python/pygd_intern.h: Handle HAVE_PYERR_NEWEXCEPTIONWITHDOC.
+	* bindings/python/pygetdata.c (gdpy_exception_list GDPY_MODINITFUNC): Add
+	docstrings to Exception objects.
+
+	* bindings/python/pygetdata.c (gdpy_copy_global_charenc): Take no arguments;
+	return a strdup'd string or NULL.
+
+	* bindings/python/pyentry.c (gdpy_entry_setthreshold): Call
+	gdpy_set_scalar_from_pyobj to properly handle scalar field codes.
+
+	* bindings/python/pygetdata.c (gdpy_string_from_pyobj): delete dup
+	parameter: now we always strdup the string.  Also clean up the encoded pyobj
+	when appropriate.
+
+	* bindings/python/pygetdata.c (gdpy_report_error): Added.  Handle GD_E_ALLOC
+	errors and gd_error_string() failures with PyErr_NoMemory().
+	* bindings/python/pygetdata.c (GDPY_MODINITFUNC): Make pygetdata.AllocError
+	an alias of MemoryError
+	* bindings/python/pygd_intern.h (GDPY_REPORT_ERROR): Deleted.
+	* bindings/python/pygd_intern.h (GDPY_CHECK_ERROR2): Call gdpy_report_error.
+	* bindings/python/pydirfile.c (gdpy_dirfile_raise): Call gdpy_report_error
+	directly.
+
+2016-05-11   D. V. Wiebe <getdata at ketiltrout.net> svn:1072
+	* bindings/python/pygetdata.h: Renamed from cpygetdata.h
+
+2016-05-11   D. V. Wiebe <getdata at ketiltrout.net> svn:1070
+	* bindings/pyghon/pygd_intern.h: Renamed from pygetdata.h
+
+2016-05-11   D. V. Wiebe <getdata at ketiltrout.net> svn:1069
+	* bindings/python/cpygetdata.h (PyDirfile_Raise)
+	bindings/python/pydirfile.c (gdpy_dirfile_raise): Added.
+
+2016-05-11   D. V. Wiebe <getdata at ketiltrout.net> svn:1067
+	* bindings/python/cpygetdata.h: Added.
+	* bindings/python/pydirfile.c (gdpy_dirfile_dirfile): Added.
+	* bindings/python/pygetdata.c (GDPY_MODINITFUNC): Create the PyCapsule
+	object if including the C API.
+	* bindings/python/pygetdata.h: Include cpygetdata.h if building the C API.
+	* bindings/python/Makefile.am: Install cpygetdata.h if appropriate.
+	* configure.ac: Check for PyCapsule and enable pygetdata C API if found.
+
+2016-04-28   D. V. Wiebe <getdata at ketiltrout.net> svn:1063
+	Python3 and PyUnicode support:
+
+	* bindings/python/pygetdata.h: Define gdpyint_fromlong, gdpyint_check,
+	gdpyint_fromlong based on python version.
+	* bindings/python/pygetdata.c (gdpy_ulong_from_pyobj gdpy_long_from_pyobj):
+	Abstractify PyInt/PyLong differences.  Everything that used to call
+	PyInt_AsLong, PyLong_AsUnsignedLong now uses one of these or the macros
+	defined in pygetdata.h as appropriate.
+
+	* bindings/python/pygetdata.h: Define gdpy_encobj_check,
+	gdpystrobj_from_string, gdpy_string_from_encobj, gdpy_encobj_from_string to
+	handle encoded strings (i.e. PyString in Python2 or PyBytes in Python3).
+	* bindings/python/pygetdata.c (gdpyobj_from_estring): Added.
+
+	* bindings/python/pygetdata.c (gdpy_string_from_pyobj gdpyobj_from_string):
+	Added, replacing most PyString_AsString and PyString_FromString calls.
+	* bindings/python/pygetdata.c (gdpy_encobj_check): Added, replacing
+	PyString_Check calls.
+	* bindings/python/pyentry.c (gdpy_dup_pystring): Deleted (now handled by
+	gdpy_string_from_pyobj).
+	* bindings/python/pygetdata.c (
+
+	* bindings/python/pygetdata.c (gdpy_path_from_pyobj_): Added for Python3.
+	* bindings/python/pygetdata.h: Define gdpy_path_from_pyobj to either
+	gdpy_string_from_pyobj (Python2) or else gdpy_path_from_pyobj_ (Python3).
+	Define gdpyobj_from_path to either PyString_FromString (Python2) or else
+	PyUnicode_DecodeFSDefault (Python3).
+
+	* bindings/python/pygetdata.c (gdpy_convert_from_pylist
+	gdpy_convert_from_pyobj): Skip GDPY_INT_AS_LONG in python3.
+
+	* bindings/python/pydirfile.c bindings/python/pyentry.c
+	bindings/python/pyfragment.c: Use PyVarObject_HEAD_INIT for PyTypeObject
+	initialisation.
+
+	* bindings/python/test/check_enc1.py bindings/python/test/check_enc2.py
+	bindings/python/test/check_enc3.py: Added.
+	
+  * bindings/python/pygetdata.h: Define GDPY_MODINITFUNC,
+	GDPY_MODINITSUCCESS, GDPY_MODINITFAILURE based on python version.  Also
+	define PyVarObject_HEAD_INIT if needed.
+	* bindings/python/pygetdata.c (GDPY_MODINITFUNC): version-agnostic name for
+	initpygetdata.  Remember the module as global gdpy_mod.
+
+	* bindings/python/pygetdata.h: Add struct gdpy_charenc_t char_enc to struct
+	gdpy_dirfile_t and struct gdpy_charenc_t char_enc.
+	* bindings/python/pygetdata.h (PYGD_CHECK_ERROR PYGD_CHECK_ERROR2
+	PYGD_REPORT_ERROR): Add ce parameter.
+	* bindings/python/pygetdata.c (GDPY_MODINITFUNC): Initialise
+	pygetdata.character_encoding to Py_None.
+	* bindings/python/pygetdata.c (gdpy_charenc_repr gdpy_parse_charenc
+	gdpy_copy_global_charenc) bindings/python/pydirfile.c
+	(gdpy_dirfile_getcharencoding gdpy_dirfile_setcharencoding)
+	bindings/python/pyentry.c (gdpy_entry_getcharencoding
+	gdpy_entry_setcharencoding): Added.
+	* bindings/python/pyentry.c (gdpy_set_entry_from_tuple
+	gdpy_set_entry_from_dict gdpy_set_scalar_from_pyobj): Add char_enc parameter.
+	* bindings/python/pydirfile.c (gdpy_dirfile_create) bindings/python/pyentry.c
+	(gdpy_entry_create): Call gdpy_copy_global_charenc to initialise
+	self->char_enc.
+	* bindings/python/pydirfile.c (gdpy_dirfile_getentry): Copy dirfile's
+	char_enc instead of the global one.
+	* bindings/python/pydirfile.c (gdpy_dirfile_init) bindings/python/pyentry.c
+	(gdpy_entry_init): Add character_encoding parameter.
+	* bindings/python/pydirfile.c bindings/python/pyentry.c
+	bindings/python/pyfragment.c: Replace "s" with "et" and, pass self->char_enc
+	where appropriate, in most PyArg_ParseTupleAndKeywords calls to automatically
+	encode Unicode objects.
+	* bindings/python/test/char_enc1.py bindings/python/test/char_enc2.py
+	bindings/python/test/char_enc3.py: Added.
+
+	* bindings/python/pydirfile.c (gdpyobj_from_strarr): Renamed from
+	gdpy_to_pystringlist, moved from pygetdata.c, and made static.
+
+	* bindings/python/pyentry.c (S1CHECK S2CHECK S3CHECK S4CHECK): Define to
+	handle unicode decoding errors.
+
+	* bindings/python/test/big_test.py (L B): Added to deal with python2/3
+	differences.
+	* bindings/python/test/big_test.py (CheckOK CheckOK2 CheckException
+	CheckException2): Use sys.exc_info()[0] instead of sys.exc_type.
+
+	* m4/python.m4 (GD_LOG_SHELL GD_PYTHON_CONFIGVAR GD_PYTHON3
+	GD_PYTHON_MIN_VERSION): Added.
+	* m4/python.m4 (GD_PYTHON): Look for python3.  Determine PYTHON_LDVERSION.
+	Don't use python-config to avoid buggy ones.  Use the right sysconfig.
+
+	* m4/python.m4 (GD_PYTHON): Figure out PYTHON_OBJECT_SUFFIX.
+	* bindings/python/Makefile.am: Use PYTHON_OBJECT_SUFFIX.
+
+	Also:
+
+	* configure.ac: Bump minimum Python2 to 2.4 due to bugs in the 2.3 branch.
+
+	* bindings/python/pygetdata.h (GDPY_CHECK_ERROR GDPY_CHECK_ERROR2
+	GDPY_REPORT_ERROR): Rename from PYGD_CHECK_ERROR PYGD_CHECK_ERROR2
+	PYGD_REPORT_ERROR for consistency.
+
+	* bindings/python/pygetdata.c (gdpylist_append): Return error if item ==
+	NULL.
+
+	* bindings/python/pyentry.c (gdpy_entry_repr): Added.
+
+	* bindings/python/pyfragment.c (gdpy_fragment_init): Fix
+	PyArg_ParseTupleAndKeywords call.
+
+	* bindings/python/pygetdata.c (gdpy_coerce_from_pyobj): Added.
+	* bindings/python/pyentry.c (gdpy_set_scalar_from_pyobj): Call
+	gdpy_string_from_pyobj or gdpy_coerce_from_pyobj to do all the work.
+	* bindings/python/pyentry.c (gdpyobj_from_scalar): Added.
+	* bindings/python/pyentry.c (gdpy_entry_getspf gdpy_entry_getm
+	gdpy_entry_getb gdpy_entry_getbitnum gdpy_entry_getnumbits
+	gdpy_entry_getdividend gdpy_entry_getshift gdpy_entry_getcountval
+	gdpy_entry_getperiod gdpy_entry_geta gdpy_entry_getparms): Call
+	gdpyobj_from_scalar.
+
+	* bindings/python/pygetdata.c (gdpy_maybe_complex): Added.
+	* bindings/python/pygetdata.c (gdpy_convert_to_pyobj): Add force_complex
+	flag.  Call gdpy_maybe_complex().
+
+	* bindings/python/pydirfile.c (gdpy_dirfile_carrays gdpy_dirfile_mcarrays):
+	Don't crash if return_type = GD_NULL.
+
+	* bindings/python/pydirfile.c (gdpy_dirfile_carraylen): Use PyErr_Warn
+	instead of PyErr_WarnEx for backwards compatibility.
+
+	* src/common.c (_GD_SetTablePath): If _GD_GrabDir fails, report the error.
+	* test/get_linterp_nodir.c: Added.
+
+	* configure.ac: Add AC_BOTTOM call.
+	* src/gd_extra_config.h: Added for Apple universal binaries
+
+	* src/include.c (_GD_Include): Pop file location from oldp.
+	* src/parse.c (_GD_ParseFragment): Use p->line for linenumbers.
+
+	* src/name.c (_GD_ValidateField): Handle CHAR_MIN != 0.
+
 2016-03-29   D. V. Wiebe <getdata at ketiltrout.net> svn:1055
 	GetData-0.9.2.1 released:
 
diff --git a/Makefile.am b/Makefile.am
index c80d666..ef7c59f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,13 +37,10 @@ clean-local:
 %.sig: %
 	gpg -abo $@ $<
 
-DISTCHECK_CONFIGURE_FLAGS = --enable-legacy-api --enable-modules \
-														--with-idl-dlm-dir="$$dc_install_base/idl" \
-														--with-perl-dir="$$dc_install_base/perl" \
-														--with-php-dir="$$dc_install_base/php" \
-														--with-python-module-dir="$$dc_install_base/python"
+DISTCHECK_CONFIGURE_FLAGS = --enable-legacy-api --enable-modules 
 
-# a locally-installed library for building and testing the IDL and matlab packages
+# a locally-installed library for building and testing the IDL and matlab
+# packages
 $(distdir)/_inst/lib/pkgconfig: $(distdir).tar.gz
 	tar -zxvf $(distdir).tar.gz
 	cd $(distdir) && \
diff --git a/Makefile.in b/Makefile.in
index 40f77d5..7da3a7f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -377,6 +377,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -426,6 +427,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -492,12 +494,7 @@ EXTRA_DIST = ChangeLog
 ACLOCAL_AMFLAGS = -I m4
 SUBDIRS = src . test bindings util man doc
 dist_doc_DATA = COPYING.DOC
-DISTCHECK_CONFIGURE_FLAGS = --enable-legacy-api --enable-modules \
-														--with-idl-dlm-dir="$$dc_install_base/idl" \
-														--with-perl-dir="$$dc_install_base/perl" \
-														--with-php-dir="$$dc_install_base/php" \
-														--with-python-module-dir="$$dc_install_base/python"
-
+DISTCHECK_CONFIGURE_FLAGS = --enable-legacy-api --enable-modules 
 
 # package lists
 PACKAGES = $(distdir).tar.gz $(distdir).tar.xz idl_$(distdir).tar.gz \
@@ -1013,7 +1010,8 @@ clean-local:
 %.sig: %
 	gpg -abo $@ $<
 
-# a locally-installed library for building and testing the IDL and matlab packages
+# a locally-installed library for building and testing the IDL and matlab
+# packages
 $(distdir)/_inst/lib/pkgconfig: $(distdir).tar.gz
 	tar -zxvf $(distdir).tar.gz
 	cd $(distdir) && \
diff --git a/NEWS b/NEWS
index ee2a0cf..977a29e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,123 @@
+New in version 0.9.3:
+
+  API Changes:
+
+  * gd_verbose_prefix() can now be used on invalid dirfiles.  Previously,
+    this function would return GD_E_BAD_DIRFILE when passed an invalid
+    DIRFILE pointer.
+
+  * BUG FIX: When trying to access a LINTERP table file in a non-existent
+    directory, GetData now reports the correct error (No such file or
+    directory).  Reported by Johanna Nagy.
+
+  Library Changes:
+
+  * GetData can now read SIE files containing the optional nine-byte header
+    (which can be created by daisie).  When read by GetData, information in
+    the header is completely ignored (because the GetData metadata contains
+    all the necessary information).  GetData never writes the header, but
+    calls to gd_putdata() will preserve an existing header.  Calls which
+    re-code the file (like gd_alter_endianness(), gd_alter_raw(), &c.) will
+    result in an existing header being deleted.
+
+  * BUG FIX: Filenames and line numbers appearing in GD_E_FORMAT error
+    strings returned by gd_error_string() are correct again.  This bug
+    also affected parser metadata sent to a registered parser callback.
+
+  * BUG FIX: On platforms where char is signed, the library no longer
+    rejects field names containing bytes with the top bit set.
+
+  Bindings Changes:
+
+  * PHP: PHP7 support has been added.
+
+  * PYTHON: Python3 support has been added based on a patch from Matthew
+    Petroff.  The earliest supported Python3 version is 3.2.  Python2 is
+    still supported from version 2.4, but Unicode support must be enabled
+    in Python2.  Support for Python 2.3 has been dropped.
+
+  * PYTHON: Under Python3, the bindings run into the issue of GetData not
+    knowing the character encoding of Dirfile metadata (the C library
+    just deals with bytes).  As a result, under Python3, by default,
+    most strings returned by the library are returned as encoded bytes()
+    objects, instead of native Unicode str() objects.  (This is true
+    under Python2 as well, but less obvious since the native Python2
+    str() object is encoded.)
+
+    To help deal with this, dirfile and entry objects now have a
+    character_encoding attribute which can be set to inform pygetdata of
+    the character encoding to use to decode the strings returned by the
+    C library into Unicode strings.  There is also a global
+    pygetdata.character_encoding object which can be used to set the
+    default encoding for newly-created pygetdata objects.  See the module
+    documentation for details.  The default for character_encoding is None,
+    implying no decoding should occur.  In Python3, paths are handled
+    separately (since the filesystem encoding may be different than the
+    GetData metadata encoding).  Error strings are decoded if possible, and
+    then ASCII encoded to ensure they're always available, regardless of
+    the capabilities of standard error.
+
+  * PYTHON: As a side-effect to the above, pygetdata now accepts unicode
+    strings (both in Python2 and in Python3).  The specified
+    character_encoding will be used to encode them to C strings before
+    being passed to the C library.  If no character_encoding is specified,
+    the current locale's default encoding will be used.
+
+  * PYTHON: When using Python 2.6 or newer, calling repr() on a
+    pygetdata.entry object now returns an eval()able string.
+
+  * PYTHON: When using Python 2.7 or newer, a very small C API is produced
+    for pygetdata.  It is defined in pygetdata.h installed alongside the
+    pygetdata module.  This C API is needed by daisie, the stand-alone SIE
+    encoding library.
+
+  * C++ BUG FIX: Including another GetData header before getdata/dirfile.h
+    no longer results in a fatal circular dependency.
+
+  * PHP BUG FIX: The numbits parameter to gd_madd_sbit() is now optional
+    and defaults to 1, as with other similar functions.
+
+  * PHP BUG FIX: Fixed a memory leak on error in gd_getdata().
+
+  * PYTHON BUG FIX: Calling pygetdata.dirfile.[m]carrays no longer crashes
+    if return_type=pygetdata.NULL.  In this case, None is returned in place
+    of the data arrays.
+  
+  * PYTHON BUG FIX: Entry objects returned by dirfile.entry() now properly
+    represent scalar field codes.
+
+  * PYTHON BUG FIX: An out-of-memory condition encountered by the
+    underlying C library is now reported using the standard MemoryError
+    exception.  Previously, the bindings would attempt to instantiate a new
+    pygetdata.AllocError exception when this happened, which wouldn't work
+    if no memory was available.  (The CPython interpreter pre-allocates an
+    instance of MemoryError to deal with this situation.)  For backwards
+    compatibility, pygetdata.AllocError is now an alias for MemoryError.
+
+  * PYTHON BUG FIX: a scalar field code string can now be assigned to the
+    threshold attribute of WINDOW entries.
+
+  * PYTHON BUG FIX: Attempting to delete various attributes from
+    pygetdata objects now either succeeds or else raises an exception,
+    instead of crashing.
+
+  Miscellaneous:
+
+  * The default install directory for the IDL, Perl, PHP, and Python
+    bindings has changed: they are now all installed under ${exec_prefix}
+    when possible.  The install directories can still be overridden by
+    ./configure options.
+
+|=========================================================================|
+
 New in version 0.9.2.1:
 
   Miscellaneous:
 
-  * This release fixes one entry in the test suite (alter_entry_scalar3r) which
-    was broken in the original 0.9.2 release.  The library and bindings are
-    unchanged (and report their version to be simply 0.9.2).  The error in
-    the test suite was reported by Dinar Valeev.
+  * This release fixes one entry in the test suite (alter_entry_scalar3r)
+    which was broken in the original 0.9.2 release.  The library and
+    bindings are unchanged (and report their version to be simply 0.9.2).
+    The error in the test suite was reported by Dinar Valeev.
 
 New in version 0.9.2:
   
diff --git a/aclocal.m4 b/aclocal.m4
index c507f20..a4804ed 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -21,7 +21,7 @@ If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
 # longlong.m4 serial 17
-dnl Copyright (C) 1999-2007, 2009-2015 Free Software Foundation, Inc.
+dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
index ad9f0d2..a498a6f 100644
--- a/bindings/Makefile.am
+++ b/bindings/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2014 D. V. Wiebe
+# Copyright (C) 2008-2014, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -60,7 +60,7 @@ SUBDIRS = . ${F77_SUBDIR} ${CXX_SUBDIR} ${IDL_SUBDIR} ${PY_SUBDIR} \
 
 make_parameters$(EXEEXT): $(make_parameters_SOURCES) \
 				    $(nodist_make_parameters_SOURCES)
-	${BUILDCC} $(DEFS) -I../src -o make_parameters$(EXEEXT) \
+	${BUILDCC} $(DEFS) -I$(top_srcdir)/src -I../src -o make_parameters$(EXEEXT) \
 		$(srcdir)/$(make_parameters_SOURCES)
 
 clean-local:
diff --git a/bindings/Makefile.in b/bindings/Makefile.in
index 3d85057..038e9e2 100644
--- a/bindings/Makefile.in
+++ b/bindings/Makefile.in
@@ -358,6 +358,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -407,6 +408,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -448,7 +450,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2008-2014 D. V. Wiebe
+# Copyright (C) 2008-2014, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -841,7 +843,7 @@ uninstall-am:
 
 make_parameters$(EXEEXT): $(make_parameters_SOURCES) \
 				    $(nodist_make_parameters_SOURCES)
-	${BUILDCC} $(DEFS) -I../src -o make_parameters$(EXEEXT) \
+	${BUILDCC} $(DEFS) -I$(top_srcdir)/src -I../src -o make_parameters$(EXEEXT) \
 		$(srcdir)/$(make_parameters_SOURCES)
 
 clean-local:
diff --git a/bindings/cxx/Makefile.am b/bindings/cxx/Makefile.am
index 2f50a7b..784c693 100644
--- a/bindings/cxx/Makefile.am
+++ b/bindings/cxx/Makefile.am
@@ -34,7 +34,8 @@ getdata_include_HEADERS = getdata/dirfile.h getdata/entry.h getdata/rawentry.h \
 													getdata/sbitentry.h getdata/polynomentry.h \
 													getdata/fragment.h getdata/divideentry.h \
 													getdata/recipentry.h getdata/carrayentry.h \
-													getdata/windowentry.h getdata/mplexentry.h
+													getdata/windowentry.h getdata/mplexentry.h \
+													getdata/types.h
 
 lib_LTLIBRARIES=libgetdata++.la
 libgetdata___la_SOURCES = dirfile.cpp bitentry.cpp carrayentry.cpp \
diff --git a/bindings/cxx/Makefile.in b/bindings/cxx/Makefile.in
index 1091735..1bef3e6 100644
--- a/bindings/cxx/Makefile.in
+++ b/bindings/cxx/Makefile.in
@@ -414,6 +414,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -463,6 +464,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -536,7 +538,8 @@ getdata_include_HEADERS = getdata/dirfile.h getdata/entry.h getdata/rawentry.h \
 													getdata/sbitentry.h getdata/polynomentry.h \
 													getdata/fragment.h getdata/divideentry.h \
 													getdata/recipentry.h getdata/carrayentry.h \
-													getdata/windowentry.h getdata/mplexentry.h
+													getdata/windowentry.h getdata/mplexentry.h \
+													getdata/types.h
 
 lib_LTLIBRARIES = libgetdata++.la
 libgetdata___la_SOURCES = dirfile.cpp bitentry.cpp carrayentry.cpp \
diff --git a/bindings/cxx/getdata/dirfile.h b/bindings/cxx/getdata/dirfile.h
index 33010da..9e93ebc 100644
--- a/bindings/cxx/getdata/dirfile.h
+++ b/bindings/cxx/getdata/dirfile.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2008-2012, 2014 D. V. Wiebe
+// Copyright (C) 2008-2012, 2014, 2016 D. V. Wiebe
 //
 ///////////////////////////////////////////////////////////////////////////
 //
@@ -22,24 +22,7 @@
 #ifndef GETDATA_DIRFILE_H
 #define GETDATA_DIRFILE_H
 
-// Enable the explicit 64-bit API (gd_getdata64() &c.)
-#ifndef GD_64BIT_API
-# define GD_64BIT_API
-#endif
-
-// Disable the legacy API since its symbols clash with us.
-#ifndef GD_NO_LEGACY_API
-# define GD_NO_LEGACY_API
-#endif
-
-// Use the C89 API since C++ compilers aren't required to support the
-// C99 _Complex keyword
-#ifndef GD_C89_API
-# define GD_C89_API
-#endif
-
-#include <getdata.h>
-
+#include <getdata/types.h>
 #include <getdata/fragment.h>
 #include <getdata/entry.h>
 #include <getdata/rawentry.h>
diff --git a/bindings/cxx/getdata/entry.h b/bindings/cxx/getdata/entry.h
index 359e23c..ad5ff46 100644
--- a/bindings/cxx/getdata/entry.h
+++ b/bindings/cxx/getdata/entry.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2008-2013, 2015 D. V. Wiebe
+// Copyright (C) 2008-2013, 2015, 2016 D. V. Wiebe
 //
 ///////////////////////////////////////////////////////////////////////////
 //
@@ -22,54 +22,13 @@
 #ifndef GETDATA_ENTRY_H
 #define GETDATA_ENTRY_H
 
-#include <getdata/dirfile.h>
+#include <getdata/types.h>
 #include <complex>
 
 namespace GetData {
 
   class Dirfile;
 
-  enum DataType {
-    Null      = GD_NULL,      Unknown    = GD_UNKNOWN,
-    UInt8     = GD_UINT8,     Int8       = GD_INT8,
-    UInt16    = GD_UINT16,    Int16      = GD_INT16,
-    UInt32    = GD_UINT32,    Int32      = GD_INT32,
-    UInt64    = GD_UINT64,    Int64      = GD_INT64,
-    Float32   = GD_FLOAT32,   Float64    = GD_FLOAT64,
-    Complex64 = GD_COMPLEX64, Complex128 = GD_COMPLEX128
-  };
-
-  enum EntryType {
-    NoEntryType       = GD_NO_ENTRY,
-    RawEntryType      = GD_RAW_ENTRY,
-    LincomEntryType   = GD_LINCOM_ENTRY,
-    LinterpEntryType  = GD_LINTERP_ENTRY,
-    BitEntryType      = GD_BIT_ENTRY,
-    MultiplyEntryType = GD_MULTIPLY_ENTRY,
-    PhaseEntryType    = GD_PHASE_ENTRY,
-    SBitEntryType     = GD_SBIT_ENTRY,
-    PolynomEntryType  = GD_POLYNOM_ENTRY,
-    ConstEntryType    = GD_CONST_ENTRY,
-    CarrayEntryType   = GD_CARRAY_ENTRY,
-    StringEntryType   = GD_STRING_ENTRY,
-    IndexEntryType    = GD_INDEX_ENTRY,
-    DivideEntryType   = GD_DIVIDE_ENTRY,
-    RecipEntryType    = GD_RECIP_ENTRY,
-    WindowEntryType   = GD_WINDOW_ENTRY,
-    MplexEntryType    = GD_MPLEX_ENTRY
-  };
-
-  enum WindOpType {
-    WindOpEq = GD_WINDOP_EQ,
-    WindOpNe = GD_WINDOP_NE,
-    WindOpGe = GD_WINDOP_GE,
-    WindOpGt = GD_WINDOP_GT,
-    WindOpLe = GD_WINDOP_LE,
-    WindOpLt = GD_WINDOP_LT,
-    WindOpSet = GD_WINDOP_SET,
-    WindOpClr = GD_WINDOP_CLR
-  };
-
   class Entry {
     friend class Dirfile;
 
diff --git a/bindings/cxx/getdata/fragment.h b/bindings/cxx/getdata/fragment.h
index fd39cba..2102b75 100644
--- a/bindings/cxx/getdata/fragment.h
+++ b/bindings/cxx/getdata/fragment.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2008-2012 D. V. Wiebe
+// Copyright (C) 2008-2012, 2016 D. V. Wiebe
 //
 ///////////////////////////////////////////////////////////////////////////
 //
@@ -22,25 +22,10 @@
 #ifndef GETDATA_FRAGMENT_H
 #define GETDATA_FRAGMENT_H
 
-#include <getdata/dirfile.h>
-#include <sys/types.h>
+#include <getdata/types.h>
 
 namespace GetData {
 
-  enum EncodingScheme {
-    AutoEncoding   = GD_AUTO_ENCODED,
-    Bzip2Encoding  = GD_BZIP2_ENCODED,
-    FlacEncoding   = GD_FLAC_ENCODED,
-    GzipEncoding   = GD_GZIP_ENCODED,
-    RawEncoding    = GD_UNENCODED,
-    SieEncoding    = GD_SIE_ENCODED,
-    SlimEncoding   = GD_SLIM_ENCODED,
-    TextEncoding   = GD_TEXT_ENCODED,
-    ZzipEncoding   = GD_ZZIP_ENCODED,
-    ZzslimEncoding = GD_ZZSLIM_ENCODED,
-    UnsupportedEncoding = GD_ENC_UNSUPPORTED
-  };
-
   class Dirfile;
 
   class Fragment {
diff --git a/bindings/cxx/getdata/types.h b/bindings/cxx/getdata/types.h
new file mode 100644
index 0000000..875902e
--- /dev/null
+++ b/bindings/cxx/getdata/types.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2008-2012, 2015, 2016 D. V. Wiebe
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// This file is part of the GetData project.
+//
+// GetData 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.
+//
+// GetData 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 GetData; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GETDATA_TYPES_H
+#define GETDATA_TYPES_H
+
+// Enable the explicit 64-bit API (gd_getdata64() &c.)
+#ifndef GD_64BIT_API
+# define GD_64BIT_API
+#endif
+
+// Disable the legacy API since its symbols clash with us.
+#ifndef GD_NO_LEGACY_API
+# define GD_NO_LEGACY_API
+#endif
+
+// Use the C89 API since C++ compilers aren't required to support the
+// C99 _Complex keyword
+#ifndef GD_C89_API
+# define GD_C89_API
+#endif
+
+#include <getdata.h>
+
+namespace GetData {
+
+  enum EncodingScheme {
+    AutoEncoding   = GD_AUTO_ENCODED,
+    Bzip2Encoding  = GD_BZIP2_ENCODED,
+    FlacEncoding   = GD_FLAC_ENCODED,
+    GzipEncoding   = GD_GZIP_ENCODED,
+    RawEncoding    = GD_UNENCODED,
+    SieEncoding    = GD_SIE_ENCODED,
+    SlimEncoding   = GD_SLIM_ENCODED,
+    TextEncoding   = GD_TEXT_ENCODED,
+    ZzipEncoding   = GD_ZZIP_ENCODED,
+    ZzslimEncoding = GD_ZZSLIM_ENCODED,
+    UnsupportedEncoding = GD_ENC_UNSUPPORTED
+  };
+
+  enum DataType {
+    Null      = GD_NULL,      Unknown    = GD_UNKNOWN,
+    UInt8     = GD_UINT8,     Int8       = GD_INT8,
+    UInt16    = GD_UINT16,    Int16      = GD_INT16,
+    UInt32    = GD_UINT32,    Int32      = GD_INT32,
+    UInt64    = GD_UINT64,    Int64      = GD_INT64,
+    Float32   = GD_FLOAT32,   Float64    = GD_FLOAT64,
+    Complex64 = GD_COMPLEX64, Complex128 = GD_COMPLEX128
+  };
+
+  enum EntryType {
+    NoEntryType       = GD_NO_ENTRY,
+    RawEntryType      = GD_RAW_ENTRY,
+    LincomEntryType   = GD_LINCOM_ENTRY,
+    LinterpEntryType  = GD_LINTERP_ENTRY,
+    BitEntryType      = GD_BIT_ENTRY,
+    MultiplyEntryType = GD_MULTIPLY_ENTRY,
+    PhaseEntryType    = GD_PHASE_ENTRY,
+    SBitEntryType     = GD_SBIT_ENTRY,
+    PolynomEntryType  = GD_POLYNOM_ENTRY,
+    ConstEntryType    = GD_CONST_ENTRY,
+    CarrayEntryType   = GD_CARRAY_ENTRY,
+    StringEntryType   = GD_STRING_ENTRY,
+    IndexEntryType    = GD_INDEX_ENTRY,
+    DivideEntryType   = GD_DIVIDE_ENTRY,
+    RecipEntryType    = GD_RECIP_ENTRY,
+    WindowEntryType   = GD_WINDOW_ENTRY,
+    MplexEntryType    = GD_MPLEX_ENTRY
+  };
+
+  enum WindOpType {
+    WindOpEq = GD_WINDOP_EQ,
+    WindOpNe = GD_WINDOP_NE,
+    WindOpGe = GD_WINDOP_GE,
+    WindOpGt = GD_WINDOP_GT,
+    WindOpLe = GD_WINDOP_LE,
+    WindOpLt = GD_WINDOP_LT,
+    WindOpSet = GD_WINDOP_SET,
+    WindOpClr = GD_WINDOP_CLR
+  };
+}
+
+#endif
+
diff --git a/bindings/cxx/internal.h b/bindings/cxx/internal.h
index 123aa7c..877de2e 100644
--- a/bindings/cxx/internal.h
+++ b/bindings/cxx/internal.h
@@ -21,7 +21,34 @@
 #ifdef HAVE_CONFIG_H
 #include "gd_config.h"
 #endif
+
+/* To avoid including stuff out of tree, we include everything here,
+ * even though getdata/dirfile.h will try to include it again.
+ */
 #undef GETDATA_LEGACY_API
+#define GD_NO_LEGACY_API
+#define GD_C89_API
+#define GD_64BIT_API
+
+#include "getdata/types.h"
+#include "getdata/fragment.h"
+#include "getdata/entry.h"
+#include "getdata/rawentry.h"
+#include "getdata/lincomentry.h"
+#include "getdata/linterpentry.h"
+#include "getdata/bitentry.h"
+#include "getdata/sbitentry.h"
+#include "getdata/phaseentry.h"
+#include "getdata/indexentry.h"
+#include "getdata/polynomentry.h"
+#include "getdata/constentry.h"
+#include "getdata/carrayentry.h"
+#include "getdata/stringentry.h"
+#include "getdata/mplexentry.h"
+#include "getdata/multiplyentry.h"
+#include "getdata/divideentry.h"
+#include "getdata/recipentry.h"
+#include "getdata/windowentry.h"
 #include "getdata/dirfile.h"
 
 #include <cstring>
diff --git a/bindings/cxx/test/Makefile.in b/bindings/cxx/test/Makefile.in
index a3db01f..fb02f8d 100644
--- a/bindings/cxx/test/Makefile.in
+++ b/bindings/cxx/test/Makefile.in
@@ -337,6 +337,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -386,6 +387,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/f77/Makefile.in b/bindings/f77/Makefile.in
index 14fdbd9..518b48c 100644
--- a/bindings/f77/Makefile.in
+++ b/bindings/f77/Makefile.in
@@ -412,6 +412,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -461,6 +462,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/f77/test/Makefile.in b/bindings/f77/test/Makefile.in
index d75abbf..bdc5e44 100644
--- a/bindings/f77/test/Makefile.in
+++ b/bindings/f77/test/Makefile.in
@@ -374,6 +374,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -423,6 +424,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/idl/Makefile.am b/bindings/idl/Makefile.am
index d22c410..b2d7ed7 100644
--- a/bindings/idl/Makefile.am
+++ b/bindings/idl/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2009, 2010, 2011, 2013 D. V. Wiebe
+# Copyright (C) 2009, 2010, 2011, 2013, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -83,7 +83,7 @@ all-local: .libs/idl_getdata.dlm
 
 # This is required to properly run the test suite
 .libs/idl_getdata.dlm: idl_getdata.dlm
-	if [ ! -e .libs ]; then mkdir -p .libs; fi
+	if [ ! -e .libs ]; then mkdir .libs; fi
 	cp $< .libs
 
 clean-local:
diff --git a/bindings/idl/Makefile.in b/bindings/idl/Makefile.in
index 2d55717..02dea04 100644
--- a/bindings/idl/Makefile.in
+++ b/bindings/idl/Makefile.in
@@ -393,6 +393,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -442,6 +443,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -483,7 +485,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2009, 2010, 2011, 2013 D. V. Wiebe
+# Copyright (C) 2009, 2010, 2011, 2013, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -978,7 +980,7 @@ all-local: .libs/idl_getdata.dlm
 
 # This is required to properly run the test suite
 .libs/idl_getdata.dlm: idl_getdata.dlm
-	if [ ! -e .libs ]; then mkdir -p .libs; fi
+	if [ ! -e .libs ]; then mkdir .libs; fi
 	cp $< .libs
 
 clean-local:
diff --git a/bindings/idl/makedlm.sh.in b/bindings/idl/makedlm.sh.in
index 1738b86..0bc7a2c 100644
--- a/bindings/idl/makedlm.sh.in
+++ b/bindings/idl/makedlm.sh.in
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright (C) 2009, 2010 D. V. Wiebe
+# Copyright (C) 2009, 2010, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -21,7 +21,7 @@
 # 
 # @configure_input@
 
-GREP=@GREP@
+LC_ALL=C
 DATE=@DATE@
 opt=$1
 in=$2
@@ -50,7 +50,7 @@ SOURCE The GetData Project <@PACKAGE_URL@>
 STRUCTURE GD_ENTRY
 EOF
 fi
-$GREP @@DLM $in | sort -k 5 | {
+grep @@DLM $in | sort -k 5 | {
 nfunc=0
 nproc=0
 while read sc magic type func idl min max key extra; do if test "$opt" = "-c"; then
diff --git a/bindings/idl/test/Makefile.in b/bindings/idl/test/Makefile.in
index 85840ef..45de824 100644
--- a/bindings/idl/test/Makefile.in
+++ b/bindings/idl/test/Makefile.in
@@ -286,6 +286,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -335,6 +336,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/make_parameters.c b/bindings/make_parameters.c
index ec2aa55..4fc852b 100644
--- a/bindings/make_parameters.c
+++ b/bindings/make_parameters.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2015 D. V. Wiebe
+/* Copyright (C) 2008-2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -400,8 +400,8 @@ void Python(void)
 
   printf(
       "/* This code is automatically generated.  "
-      "Changes made here will be lost. */\n#define NO_IMPORT_ARRAY\n"
-      "#include \"pygetdata.h\"\n"
+      "Changes made here will be lost. */\n"
+      "#include \"gdpy_intern.h\"\n"
       "const struct gdpy_constant_t gdpy_constant_list[] = {\n");
   
   for (i = 0; constant_list[i].lname != NULL; ++i)
@@ -576,9 +576,8 @@ void PHP(void)
   
   for (i = 0; constant_list[i].lname != NULL; ++i)
     if (constant_list[i].type != GDMP_DEPERR)
-      printf("zend_register_long_constant(ZEND_STRS(\"%s\"), %li, CONST_CS, "
-          "module_number TSRMLS_CC);", constant_list[i].lname,
-          constant_list[i].value);
+      printf("GDPHP_REGISTER_LONG_CONSTANT(\"%s\", %li, module_number); ",
+          constant_list[i].lname, constant_list[i].value);
 
   puts("dreturnvoid();}");
 }
diff --git a/bindings/matlab/Makefile.am b/bindings/matlab/Makefile.am
index b95953f..108ca5c 100644
--- a/bindings/matlab/Makefile.am
+++ b/bindings/matlab/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2015 D. V. Wiebe
+# Copyright (C) 2013-2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -96,7 +96,7 @@ libgetdata_matlab_la_CPPFLAGS=${MATLAB_CPPFLAGS} ${AM_CPPFLAGS}
 libgetdata_matlab_la_LDFLAGS=-version-info @MATLABGETDATA_VERSION@
 
 %.m: %.c ${srcdir}/doc.tail
-	${GREP} '^ %' $< | ${SED} -e 's/^ //' > $@
+	grep '^ %' $< | sed -e 's/^ //' > $@
 	cat ${srcdir}/doc.tail >> $@
 
 %. at mexext@: %.c libgetdata-matlab.la
diff --git a/bindings/matlab/Makefile.in b/bindings/matlab/Makefile.in
index c685f02..a15afd5 100644
--- a/bindings/matlab/Makefile.in
+++ b/bindings/matlab/Makefile.in
@@ -393,6 +393,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -442,6 +443,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -483,7 +485,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2013-2015 D. V. Wiebe
+# Copyright (C) 2013-2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -1046,7 +1048,7 @@ uninstall-am: uninstall-dist_matlabSCRIPTS uninstall-libLTLIBRARIES \
 
 
 %.m: %.c ${srcdir}/doc.tail
-	${GREP} '^ %' $< | ${SED} -e 's/^ //' > $@
+	grep '^ %' $< | sed -e 's/^ //' > $@
 	cat ${srcdir}/doc.tail >> $@
 
 %. at mexext@: %.c libgetdata-matlab.la
diff --git a/bindings/matlab/getdata_constants.m b/bindings/matlab/getdata_constants.m
index 0def650..674eff8 100644
--- a/bindings/matlab/getdata_constants.m
+++ b/bindings/matlab/getdata_constants.m
@@ -31,7 +31,7 @@ function GD = getdata_constants()
 %   See also GETDATA
 
   GD = struct(...
-    'VERSION', '0.9.2', ...
+    'VERSION', '0.9.3a', ...
     'E_OK', int32(0), ...
     'E_FORMAT', int32(2), ...
     'E_CREAT', int32(4), ...
diff --git a/bindings/matlab/make_contents.sh.in b/bindings/matlab/make_contents.sh.in
index 1d8dcd7..bc36d6b 100644
--- a/bindings/matlab/make_contents.sh.in
+++ b/bindings/matlab/make_contents.sh.in
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright (C) 2013 D. V. Wiebe
+# Copyright (C) 2013, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -21,11 +21,9 @@
 # 
 # @configure_input@
 
-AWK=@AWK@
+LC_ALL=C
 DATE=@DATE@
-GREP=@GREP@
 PRINTF=@PRINTF@
-SED=@SED@
 VERSION=@GETDATA_MAJOR at .@GETDATA_MINOR@
 REVISION=R at GETDATA_REVISION@@GETDATA_VERSION_SUFFIX@
 SRCDIR=$1
@@ -48,8 +46,8 @@ if test "x$PRINTF" != "xnot found"; then
   (
   ls getdata*.m gd_*.m ${BUILT_FILES} | while read x; do
     ${PRINTF} "%%   %-22s - %s\n" \
-      "`basename $x | ${AWK} 'BEGIN{FS="."} { print toupper($1) }'`" \
-      "`${GREP} -m 1 '^%' $x | ${SED} 's/% *[A-Z_]* *\(.*\)/\1/'`"
+      "`expr "./$x" : '.*\/\(.*\).m' | tr '[a-z]' '[A-Z]'`" \
+      "`grep '^%' $x | head -n 1 | sed 's/% *[A-Z_]* *\(.*\)/\1/'`"
   done
   ) | sort
 fi
diff --git a/bindings/matlab/test/Makefile.in b/bindings/matlab/test/Makefile.in
index 32bfe99..f241026 100644
--- a/bindings/matlab/test/Makefile.in
+++ b/bindings/matlab/test/Makefile.in
@@ -286,6 +286,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -335,6 +336,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/matlab/test/test.sh b/bindings/matlab/test/test.sh
index 1aa0192..5ae9218 100755
--- a/bindings/matlab/test/test.sh
+++ b/bindings/matlab/test/test.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-s=`basename $2 .m`
+s=`expr ./$2 : '.*/\(.*\).m'`
 rm -f ./test_failed
 $1 -nodesktop -nodisplay -nosplash -nojvm -r "$s; quit;"
 
diff --git a/bindings/perl/Makefile.am b/bindings/perl/Makefile.am
index 58cf932..5e0dec7 100644
--- a/bindings/perl/Makefile.am
+++ b/bindings/perl/Makefile.am
@@ -53,7 +53,7 @@ build/build.stamp: src/Makefile.PL src/GetData.xs src/typemap
 	mkdir build/lib
 	touch $@
 
-# this enssures that the test files are present and up-to-date
+# this ensures that the test files are present and up-to-date
 build/test.stamp: build/build.stamp ${plTESTS}
 	[ -e build/t ] || mkdir build/t
 	cp -r $(srcdir)/t/* build/t
diff --git a/bindings/perl/Makefile.in b/bindings/perl/Makefile.in
index 5b83af0..ed08476 100644
--- a/bindings/perl/Makefile.in
+++ b/bindings/perl/Makefile.in
@@ -297,6 +297,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -346,6 +347,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -748,7 +750,7 @@ build/build.stamp: src/Makefile.PL src/GetData.xs src/typemap
 	mkdir build/lib
 	touch $@
 
-# this enssures that the test files are present and up-to-date
+# this ensures that the test files are present and up-to-date
 build/test.stamp: build/build.stamp ${plTESTS}
 	[ -e build/t ] || mkdir build/t
 	cp -r $(srcdir)/t/* build/t
diff --git a/bindings/php/Makefile.in b/bindings/php/Makefile.in
index 309826d..e95c314 100644
--- a/bindings/php/Makefile.in
+++ b/bindings/php/Makefile.in
@@ -388,6 +388,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -437,6 +438,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/php/getdata.c b/bindings/php/getdata.c
index dca2c2b..fdea031 100644
--- a/bindings/php/getdata.c
+++ b/bindings/php/getdata.c
@@ -24,13 +24,124 @@
 
 /* corresponding type of the PHP integer */
 #if SIZEOF_LONG == 4
-#define GDPHP_LONG GD_INT32
+#define GDPHP_LONG_TYPE GD_INT32
 typedef int32_t gdphp_long_t;
 #elif SIZEOF_LONG == 8
-#define GDPHP_LONG GD_INT64
+#define GDPHP_LONG_TYPE GD_INT64
 typedef int64_t gdphp_long_t;
 #endif
 
+/* PHP7 malarkey */
+#if ZEND_MODULE_API_NO >= 20151012
+/* PHP7 */
+
+/* Resources are now bona fide zvals */
+#define GDPHP_RESOURCE zend_resource
+#define GDPHP_RET_RES(r,le) RETVAL_RES(zend_register_resource((r),(le)))
+#define gdphp_fetch_resource(z) zend_fetch_resource2_ex((z), "Dirfile", \
+    le_gdphp_dirfile, le_gdphp_dirfile_persist)
+#define gdphp_list_close(z) zend_list_close(Z_RES_P(z))
+
+/* Strings now always duplicate */
+#define gdphp_add_index_string add_index_string
+#define GDPHP_RET_STRL_COPY RETURN_STRINGL
+#define GDPHP_RET_STR_COPY(s) GDPHP_RET_STRL_COPY((s),strlen(s))
+#define GDPHP_STRINGL ZVAL_STRINGL
+#define GDPHP_COPY_DATA(z,s,l,d) do { \
+  ZVAL_STRINGL((z),(s),(l)); \
+  if (!(d)) efree(s); \
+} while(0)
+#define GDPHP_RETVAL_STRING RETVAL_STRING
+#define gdphp_add_assoc_string add_assoc_string
+
+/* Hashes basically suck */
+#define GDPHP_HASH_FINDL(v,ht,key,len) \
+  (v = zend_hash_str_find((ht), (key), len))
+#define GDPHP_HASH_ADD(ht,key,len,data) \
+  zend_hash_str_update_mem((ht), (key), (len), &(data), sizeof(data))
+#define GDPHP_FIND_RES(v,ht,key,len) \
+  (v = zend_hash_str_find_ptr((ht), (key), len))
+#define GDPHP_HASH_INDEX_FIND(v,ht,h) (v = zend_hash_index_find((ht),(h)))
+#define GDPHP_HASH_KEY_DECL(n) zend_string* n
+#define GDPHP_HASH_GET_CURRENT_KEY(ht,key,idx,pos) \
+  zend_hash_get_current_key_ex(ht, &key, &idx, &pos)
+#define GDPHP_HASH_GET_CURRENT_DATA(v,ht,pos) \
+  (v = zend_hash_get_current_data_ex(ht, &pos))
+#define GDPHP_HASH_FIND(v,ht,key) GDPHP_HASH_FINDL((v),(ht),(key),strlen(key))
+
+/* Booleans are gone */
+#define Z_BVAL_P(z) ((Z_TYPE_P(z) == IS_TRUE) ? 1 : 0)
+#define BOOL_CASE /**/
+
+/* Most things that used to use zval** now just uses zval* */
+#define GDPHP_ZVALP zval*
+#define ZP(z) z
+#define ZR(z) z
+
+/* We now can allocate zvals directly on the stack */
+#define GDPHP_ZVAL zval
+#define GDPHP_ZVAL_NULL(z) zval z
+#define GDPHP_INIT_ZVAL(z) /**/
+#define RZ(z) &z
+#define GDPHP_PTR_DTOR(z) /**/
+
+/* Changes to zend_parse_parameters */
+#define GDPHP_LONG zend_long
+#define GDPHP_SLEN size_t
+#define ZPP_Z "z"
+
+#else
+/* PHP5 */
+
+#define gdphp_fetch_resource(z) zend_fetch_resource(&(z) TSRMLS_CC, -1, \
+    "Dirfile", NULL, 2, le_gdphp_dirfile, le_gdphp_dirfile_persist)
+#define gdphp_add_index_string(a,i,s) add_index_string((a),(i),(s),1)
+#define GDPHP_RET_STRL_COPY(s,l) RETURN_STRINGL((s), (l), 1)
+#define GDPHP_RET_STR_COPY(s) RETURN_STRING((s), 1)
+#define GDPHP_RET_RES(r,le) ZEND_REGISTER_RESOURCE(return_value, (r), (le))
+#define GDPHP_HASH_FINDL(v,ht,key,len) \
+  (zend_hash_find((ht), (key), (len), (void**)&(v)) == SUCCESS)
+#define GDPHP_RESOURCE zend_rsrc_list_entry
+#define GDPHP_HASH_ADD(ht,key,len,data) \
+  zend_hash_add((ht), (key), (len), &(data), sizeof(data), NULL)
+#define GDPHP_FIND_RES GDPHP_HASH_FINDL
+#define GDPHP_RETVAL_STRING(s) RETVAL_STRING(s, 1)
+#define gdphp_list_close(z) zend_list_delete(Z_LVAL_P(z))
+#define GDPHP_STRINGL(z,s,l) ZVAL_STRINGL((z),(s),(l),1)
+#define GDPHP_COPY_DATA(z,s,l,d) do { \
+  if (!d) { /* trim excess */ \
+    void *ptr = erealloc((s), (l)); \
+    if (ptr) data = ptr; \
+  } \
+  ZVAL_STRINGL((z),(s),(l),1); \
+} while(0);
+#define GDPHP_ZVALP zval**
+#define ZP(z) *z
+#define ZR(z) &z
+#define GDPHP_HASH_INDEX_FIND(v,ht,h) \
+  (zend_hash_index_find((ht),(h), (void**)&(v)) == SUCCESS)
+#define GDPHP_HASH_KEY_DECL(n) char*n; unsigned int n ## _len
+#define GDPHP_HASH_GET_CURRENT_KEY(ht,key,idx,pos) \
+  zend_hash_get_current_key_ex(ht, &key, &key ## _len, &idx, 0, &pos)
+#define GDPHP_HASH_GET_CURRENT_DATA(v,ht,pos) \
+  (zend_hash_get_current_data_ex(ht, (void*)&v, &pos) == SUCCESS)
+#define BOOL_CASE case IS_BOOL:
+#define gdphp_add_assoc_string(a,k,s) add_assoc_string((a),(k),(s),1)
+#define GDPHP_HASH_FIND(v,ht,key) GDPHP_HASH_FINDL((v),(ht),(key),strlen(key)+1)
+
+#define GDPHP_ZVAL zval*
+#define GDPHP_ZVAL_NULL(z) zval* z = NULL
+#define GDPHP_INIT_ZVAL ALLOC_INIT_ZVAL
+#define RZ(z) z
+#define GDPHP_PTR_DTOR(z) zval_ptr_dtor(&z)
+
+#define GDPHP_LONG long
+#define GDPHP_SLEN int
+#define ZPP_Z "Z"
+
+#endif
+
+
 /* PHP globals */
 ZEND_BEGIN_MODULE_GLOBALS(getdata)
   zend_bool degrade_complex;
@@ -56,9 +167,9 @@ PHP_INI_BEGIN()
 PHP_INI_END()
 
 /* Common idioms */
+
 #define GDPHP_FETCH_DIRFILE(r, z) do { \
-  r = (gdphp_dirfile*)zend_fetch_resource(&(z) TSRMLS_CC, -1, "Dirfile", NULL, \
-      2, le_gdphp_dirfile, le_gdphp_dirfile_persist); \
+  r = (gdphp_dirfile*)gdphp_fetch_resource(z); \
   if (!r) { GDPHP_RETURN_F; } \
 } while(0)
 
@@ -95,8 +206,7 @@ PHP_INI_END()
   D = gdphp_dirfile_rsrc->D; \
 } while(0)
 
-#define dtracephp() dtrace("%i, %p, %p, %p, %i", ht, return_value, \
-    return_value_ptr, this_ptr, return_value_used)
+#define dtracephp() dtrace("..., %p, ...", return_value);
 
 struct gdphp_din {
   void *data;
@@ -154,7 +264,7 @@ typedef struct gdphp_dirfile_ {
   DIRFILE *D;
   char *callback;
   int callback_len;
-  zval **callback_data;
+  GDPHP_ZVALP callback_data;
   char *key;
   int key_len;
 
@@ -165,7 +275,7 @@ typedef struct gdphp_dirfile_ {
 int le_gdphp_dirfile;
 int le_gdphp_dirfile_persist;
 
-static void gdphp_dirfile_dtor(zend_rsrc_list_entry *z TSRMLS_DC)
+static void gdphp_dirfile_dtor(GDPHP_RESOURCE *z TSRMLS_DC)
 {
   dtracetsrm("%p", z);
 
@@ -175,15 +285,15 @@ static void gdphp_dirfile_dtor(zend_rsrc_list_entry *z TSRMLS_DC)
 
   if (r->callback)
     efree(r->callback);
-  if (r->callback_data && *(r->callback_data))
-    Z_DELREF_PP(r->callback_data);
+  if (r->callback_data && ZP(r->callback_data))
+    Z_DELREF_P(ZP(r->callback_data));
   efree(r->key);
   efree(r);
 
   dreturnvoid();
 }
 
-static void gdphp_dirfile_pdtor(zend_rsrc_list_entry *z TSRMLS_DC)
+static void gdphp_dirfile_pdtor(GDPHP_RESOURCE *z TSRMLS_DC)
 {
   dtracetsrm("%p", z);
 
@@ -194,7 +304,7 @@ static void gdphp_dirfile_pdtor(zend_rsrc_list_entry *z TSRMLS_DC)
   if (r->callback)
     pefree(r->callback, 1);
   if (r->callback_data)
-    Z_DELREF_PP(r->callback_data);
+    Z_DELREF_P(ZP(r->callback_data));
   pefree(r->key, 1);
   pefree(r, 1);
 
@@ -208,13 +318,25 @@ static int gdphp_callback(gd_parser_data_t *pdata, void *extra)
   int new_line = 0;
   char *ptr;
   gdphp_dirfile *r = (gdphp_dirfile*)extra;
-  zval *response;
-  zval *function_name;
   zval *zpdata;
+  GDPHP_ZVAL function_name;
+  GDPHP_ZVAL response;
+#if ZEND_MODULE_API_NO >= 20151012
+  zval params[2];
+#else
   zval **params[2] = { &zpdata, r->callback_data };
+#endif
 
   dtrace("%p, %p", pdata, r->callback_data);
 
+#if ZEND_MODULE_API_NO >= 20151012
+  zpdata = &params[0];
+  if (r->callback_data == NULL) 
+    ZVAL_UNDEF(params + 1);
+  else
+    ZVAL_COPY_VALUE(params + 1, r->callback_data);
+#endif
+
   if (r->callback == NULL) { /* nothing to do */
     dreturn("%i", GD_SYNTAX_ABORT);
     return GD_SYNTAX_ABORT;
@@ -223,33 +345,33 @@ static int gdphp_callback(gd_parser_data_t *pdata, void *extra)
   TSRMLS_FETCH();
 
   /* make a zval for the function name */
-  ALLOC_INIT_ZVAL(function_name);
-  ZVAL_STRINGL(function_name, r->callback, r->callback_len, 1);
+  GDPHP_INIT_ZVAL(function_name);
+  GDPHP_STRINGL(RZ(function_name), r->callback, r->callback_len);
 
   /* make a hashtable for the parser data */
-  ALLOC_INIT_ZVAL(zpdata);
+  GDPHP_INIT_ZVAL(zpdata);
   array_init(zpdata);
   add_assoc_long(zpdata, "suberror", pdata->suberror);
   add_assoc_long(zpdata, "linenum", pdata->linenum);
-  add_assoc_string(zpdata, "line", pdata->line, 1);
-  add_assoc_string(zpdata, "filename", (char*)pdata->filename, 1);
+  gdphp_add_assoc_string(zpdata, "line", pdata->line);
+  gdphp_add_assoc_string(zpdata, "filename", (char*)pdata->filename);
 
   /* call the callback */
-  if (call_user_function_ex(CG(function_table), NULL, function_name, &response,
-        2, params, 0, NULL TSRMLS_CC) != SUCCESS)
+  if (call_user_function_ex(CG(function_table), NULL, RZ(function_name),
+        &response, 2, params, 0, NULL TSRMLS_CC) != SUCCESS)
   {
     zend_error(E_ERROR, "Unable to execute GetData callback");
   }
 
-  zval_ptr_dtor(&function_name);
+  GDPHP_PTR_DTOR(function_name);
 
   /* interpret the response */
-  switch (Z_TYPE_P(response)) {
+  switch (Z_TYPE_P(RZ(response))) {
     case IS_LONG:
-      sem = (int)Z_LVAL_P(response);
+      sem = (int)Z_LVAL_P(RZ(response));
       break;
     case IS_STRING: /* this means rescan */
-      ptr = strdup(Z_STRVAL_P(response));
+      ptr = strdup(Z_STRVAL_P(RZ(response)));
       if (ptr == NULL)
         zend_error(E_ERROR, "Out of memory");
       pdata->line = ptr;
@@ -263,11 +385,9 @@ static int gdphp_callback(gd_parser_data_t *pdata, void *extra)
   /* copy the line out of the zpdata hash, if necessary and possible */
   if (sem == GD_SYNTAX_RESCAN && new_line == 0) {
     zval *line;
-    if (zend_hash_find(Z_ARRVAL_P(zpdata), "line", sizeof("line"),
-          (void**)&line) == SUCCESS)
-    {
+    if (GDPHP_HASH_FIND(line, Z_ARRVAL_P(zpdata), "line")) {
       if (Z_TYPE_P(line) == IS_STRING) {
-        ptr = strdup(Z_STRVAL_P(response));
+        ptr = strdup(Z_STRVAL_P(RZ(response)));
         if (ptr == NULL)
           zend_error(E_ERROR, "Out of memory");
         pdata->line = ptr;
@@ -275,7 +395,7 @@ static int gdphp_callback(gd_parser_data_t *pdata, void *extra)
     }
   }
 
-  zval_ptr_dtor(&zpdata);
+  zval_ptr_dtor(ZR(zpdata));
 
   dreturn("%i", sem);
   return sem;
@@ -283,7 +403,8 @@ static int gdphp_callback(gd_parser_data_t *pdata, void *extra)
 
 /* create a dirfile resource */
 static gdphp_dirfile *gdphp_open(const char *dirfilename, int len, long flags,
-    const char *callback, int callback_len, zval **callback_data, int persist)
+    const char *callback, int callback_len, GDPHP_ZVALP callback_data,
+    int persist)
 {
   gdphp_dirfile *r;
   DIRFILE *D;
@@ -306,7 +427,7 @@ static gdphp_dirfile *gdphp_open(const char *dirfilename, int len, long flags,
   }
 
   if (callback_data) {
-    Z_ADDREF_PP(callback_data);
+    Z_ADDREF_P(ZP(callback_data));
     r->callback_data = callback_data;
   }
 
@@ -332,7 +453,7 @@ static zval *gdphp_from_complex(zval *z, double r, double i)
   TSRMLS_FETCH();
 
   if (z == NULL)
-    ALLOC_INIT_ZVAL(z);
+    GDPHP_INIT_ZVAL(z);
 
   if (i == 0 && GDPHP_G(degrade_complex)) {
     ZVAL_DOUBLE(z, r);
@@ -350,9 +471,11 @@ static zval *gdphp_from_complex(zval *z, double r, double i)
 static void gdphp_add_assoc_complex(zval *z, const char *key, double r,
     double i)
 {
+  GDPHP_ZVAL_NULL(tmp);
+
   dtrace("%p, \"%s\", %g, %g", z, key, r, i);
 
-  add_assoc_zval(z, key, gdphp_from_complex(NULL, r, i));
+  add_assoc_zval(z, key, gdphp_from_complex(RZ(tmp), r, i));
 
   dreturnvoid();
 }
@@ -361,18 +484,20 @@ static void gdphp_add_assoc_complex(zval *z, const char *key, double r,
 static void gdphp_add_assoc_cmparray(zval *z, const char *key, double *l,
     int n)
 {
-  zval *a;
+  GDPHP_ZVAL a;
   int i;
+  GDPHP_ZVAL_NULL(tmp);
 
   dtrace("%p, \"%s\", %p, %i", z, key, l, n);
 
-  ALLOC_INIT_ZVAL(a);
-  array_init(a);
+  GDPHP_INIT_ZVAL(a);
+  array_init(RZ(a));
 
   for (i = 0; i < n; ++i)
-    add_index_zval(a, i, gdphp_from_complex(NULL, l[i * 2], l[i * 2 + 1]));
+    add_index_zval(RZ(a), i, gdphp_from_complex(RZ(tmp), l[i * 2],
+          l[i * 2 + 1]));
 
-  add_assoc_zval(z, key, a);
+  add_assoc_zval(z, key, RZ(a));
 
   dreturnvoid();
 }
@@ -381,18 +506,18 @@ static void gdphp_add_assoc_cmparray(zval *z, const char *key, double *l,
 static void gdphp_add_assoc_string_arr(zval *z, const char *key, char **l,
     int n)
 {
-  zval *a;
+  GDPHP_ZVAL a;
   int i;
 
   dtrace("%p, \"%s\", %p, %i", z, key, l, n);
 
-  ALLOC_INIT_ZVAL(a);
-  array_init(a);
+  GDPHP_INIT_ZVAL(a);
+  array_init(RZ(a));
 
   for (i = 0; i < n; ++i)
-    add_index_string(a, i, l[i], 1);
+    gdphp_add_index_string(RZ(a), i, l[i]);
 
-  add_assoc_zval(z, key, a);
+  add_assoc_zval(z, key, RZ(a));
 
   dreturnvoid();
 }
@@ -402,25 +527,25 @@ static void gdphp_add_assoc_scalars(zval *z, gd_entry_t *E, unsigned mask)
 {
   int i;
 
-  zval *scalar;
-  zval *lm;
+  GDPHP_ZVAL scalar;
+  GDPHP_ZVAL lm;
 
   dtrace("%p, %p, 0x%X", z, E, mask);
 
-  ALLOC_INIT_ZVAL(scalar);
-  array_init(scalar);
+  GDPHP_INIT_ZVAL(scalar);
+  array_init(RZ(scalar));
 
   for (i = 0; i <= GD_MAX_POLYORD; ++i)
     if (mask & (1 << i))
       if (E->scalar[i]) {
-        ALLOC_INIT_ZVAL(lm);
-        array_init(lm);
-        add_index_string(lm, 0, E->scalar[i], 1);
-        add_index_long(lm, 1, E->scalar_ind[i]);
-        add_index_zval(scalar, i, lm);
+        GDPHP_INIT_ZVAL(lm);
+        array_init(RZ(lm));
+        gdphp_add_index_string(RZ(lm), 0, E->scalar[i]);
+        add_index_long(RZ(lm), 1, E->scalar_ind[i]);
+        add_index_zval(RZ(scalar), i, RZ(lm));
       }
 
-  add_assoc_zval(z, "scalar", scalar);
+  add_assoc_zval(z, "scalar", RZ(scalar));
 
   dreturnvoid();
 }
@@ -432,7 +557,7 @@ static void gdphp_from_entry(zval *z, gd_entry_t *E)
   
   array_init(z);
 
-  add_assoc_string(z, "field", E->field, 1);
+  gdphp_add_assoc_string(z, "field", E->field);
   add_assoc_long(z, "field_type", E->field_type);
   add_assoc_long(z, "fragment_index", E->fragment_index);
   switch (E->field_type) {
@@ -461,7 +586,7 @@ static void gdphp_from_entry(zval *z, gd_entry_t *E)
       break;
     case GD_LINTERP_ENTRY:
       gdphp_add_assoc_string_arr(z, "in_fields", E->in_fields, 1);
-      add_assoc_string(z, "table", E->EN(linterp,table), 1);
+      gdphp_add_assoc_string(z, "table", E->EN(linterp,table));
       break;
     case GD_MULTIPLY_ENTRY:
     case GD_DIVIDE_ENTRY:
@@ -571,14 +696,14 @@ static int gdphp_to_complex(double *r, double *i, zval *z, int complain,
   n = zend_hash_num_elements(a);
 
   if (n == 2) {
-    zval **d;
+    GDPHP_ZVALP d;
 
-    if (zend_hash_index_find(a, 0, (void**)&d) == SUCCESS)
-      if (gdphp_to_datum(r, GD_FLOAT64, *d, 0, ctx) == 0)
+    if (GDPHP_HASH_INDEX_FIND(d, a, 0))
+      if (gdphp_to_datum(r, GD_FLOAT64, ZP(d), 0, ctx) == 0)
         converted++;
 
-    if (zend_hash_index_find(a, 1, (void**)&d) == SUCCESS)
-      if (gdphp_to_datum(i, GD_FLOAT64, *d, 0, ctx) == 0)
+    if (GDPHP_HASH_INDEX_FIND(d, a, 1))
+      if (gdphp_to_datum(i, GD_FLOAT64, ZP(d), 0, ctx) == 0)
         converted++;
   }
 
@@ -605,8 +730,7 @@ static gd_type_t gdphp_get_type(zval *z, struct gdphp_context_t *ctx)
     case IS_NULL:
       t = GD_NULL;
       break;
-    case IS_LONG:
-    case IS_BOOL:
+    case IS_LONG: BOOL_CASE
       t = GD_INT64;
       break;
     case IS_DOUBLE:
@@ -626,7 +750,7 @@ static gd_type_t gdphp_get_type(zval *z, struct gdphp_context_t *ctx)
     switch (Z_TYPE_P(src)) { \
       double r, i; \
       case IS_NULL:               ((t*)dst)[0] = ((t*)dst)[1] = 0; break; \
-      case IS_LONG: case IS_BOOL: ((t*)dst)[0] = Z_LVAL_P(src); \
+      case IS_LONG: BOOL_CASE     ((t*)dst)[0] = Z_LVAL_P(src); \
                                   ((t*)dst)[1] = 0; break; \
       case IS_DOUBLE:             ((t*)dst)[0] = Z_DVAL_P(src); \
                                   ((t*)dst)[1] = 0; break; \
@@ -640,7 +764,7 @@ static gd_type_t gdphp_get_type(zval *z, struct gdphp_context_t *ctx)
   do { \
     switch (Z_TYPE_P(src)) { \
       double r, i; \
-      case IS_LONG: case IS_BOOL: *((t*)dst) = Z_LVAL_P(src); break; \
+      case IS_LONG: BOOL_CASE     *((t*)dst) = Z_LVAL_P(src); break; \
       case IS_DOUBLE:             *((t*)dst) = Z_DVAL_P(src); break; \
       case IS_ARRAY: gdphp_to_complex(&r, &i, src, 1, ctx); \
                      *((t*)dst) = r; break; \
@@ -684,7 +808,7 @@ static gd_type_t gdphp_to_datum_and_type(void *datum, zval *z,
 
   switch (Z_TYPE_P(z)) {
     case IS_LONG:
-      t = GDPHP_LONG;
+      t = GDPHP_LONG_TYPE;
       *((gdphp_long_t*)datum) = Z_LVAL_P(z);
       break;
     case IS_DOUBLE:
@@ -756,10 +880,9 @@ static int gdphp_convert_cmparray(double *out, zval *z, int min, int max,
 {
   HashTable *a = Z_ARRVAL_P(z);
   HashPosition i;
-  zval **d = NULL;
+  GDPHP_ZVALP d = NULL;
   int n = -1;
-  unsigned key_len;
-  char *key;
+  GDPHP_HASH_KEY_DECL(key);
   long index;
 
   int *have;
@@ -776,19 +899,17 @@ static int gdphp_convert_cmparray(double *out, zval *z, int min, int max,
 
   /* populate the C array */
   for (zend_hash_internal_pointer_reset_ex(a, &i);
-      zend_hash_get_current_data_ex(a, (void*)&d, &i) == SUCCESS;
+      GDPHP_HASH_GET_CURRENT_DATA(d, a, i);
       zend_hash_move_forward_ex(a, &i))
   {
     /* check key */
-    if (zend_hash_get_current_key_ex(a, &key, &key_len, (ulong*)&index, 0, &i)
-        == HASH_KEY_IS_STRING)
-    {
+    if (GDPHP_HASH_GET_CURRENT_KEY(a, key, index, i) == HASH_KEY_IS_STRING) {
       GDPHP_DIE(ctx, "cannot use associative array");
     } else if (index < 0 || index >= max)
       GDPHP_DIE2(ctx, "bad array index (%li)", index);
 
     if (!have[index]) {
-      gdphp_to_datum(out + index * 2, GD_COMPLEX128, *d, 1, ctx);
+      gdphp_to_datum(out + index * 2, GD_COMPLEX128, ZP(d), 1, ctx);
       have[index] = 1;
     }
   }
@@ -817,10 +938,9 @@ static int gdphp_convert_nsarray(char **out, zval *z, int min, int max,
 {
   HashTable *a = Z_ARRVAL_P(z);
   HashPosition i;
-  zval **d = NULL;
+  GDPHP_ZVALP d = NULL;
   int n = -1;
-  unsigned key_len;
-  char *key;
+  GDPHP_HASH_KEY_DECL(key);
   long index;
 
   dtracectx("%p, %p, %i, %i", out, z, min, max);
@@ -830,21 +950,20 @@ static int gdphp_convert_nsarray(char **out, zval *z, int min, int max,
 
   /* populate the C array */
   for (zend_hash_internal_pointer_reset_ex(a, &i);
-      zend_hash_get_current_data_ex(a, (void*)&d, &i) == SUCCESS;
+      GDPHP_HASH_GET_CURRENT_DATA(d, a, i);
       zend_hash_move_forward_ex(a, &i))
   {
     /* check key */
-    if (zend_hash_get_current_key_ex(a, &key, &key_len, (ulong*)&index, 0, &i)
-        == HASH_KEY_IS_STRING)
+    if (GDPHP_HASH_GET_CURRENT_KEY(a, key, index, i) == HASH_KEY_IS_STRING)
     {
       GDPHP_DIE(ctx, "cannot use associative array");
     } else if (index < 0 || index >= max)
       GDPHP_DIE2(ctx, "bad array index (%li)", index);
 
-    if (Z_TYPE_PP(d) != IS_STRING)
+    if (Z_TYPE_P(ZP(d)) != IS_STRING)
       GDPHP_DIE(ctx, "string array required");
 
-    out[index] = Z_STRVAL_PP(d);
+    out[index] = Z_STRVAL_P(ZP(d));
   }
 
   /* check for holes and calculate n */
@@ -868,9 +987,8 @@ static void gdphp_convert_array(struct gdphp_din *din, zval *zdata,
 {
   HashTable *a = Z_ARRVAL_P(zdata);
   HashPosition i;
-  zval **d = NULL;
-  char *key;
-  unsigned key_len;
+  GDPHP_ZVALP d = NULL;
+  GDPHP_HASH_KEY_DECL(key);
   long index;
 
   dtracectx("%p, %p", din, zdata);
@@ -879,13 +997,11 @@ static void gdphp_convert_array(struct gdphp_din *din, zval *zdata,
 
   /* pass 1: validate data and determine ns */
   for (zend_hash_internal_pointer_reset_ex(a, &i);
-      zend_hash_get_current_data_ex(a, (void*)&d, &i) == SUCCESS;
+      GDPHP_HASH_GET_CURRENT_DATA(d, a, i);
       zend_hash_move_forward_ex(a, &i))
   {
     /* make sure this isn't an associative array */
-    if (zend_hash_get_current_key_ex(a, &key, &key_len, (ulong*)&index, 0, &i)
-        == HASH_KEY_IS_STRING)
-    {
+    if (GDPHP_HASH_GET_CURRENT_KEY(a, key, index, i) == HASH_KEY_IS_STRING) {
       GDPHP_DIE(ctx, "cannot use associative arrays");
     } else if (index < 0) /* does zend_hash_get_current_key_ex return ulong
                              or a long? */
@@ -895,7 +1011,7 @@ static void gdphp_convert_array(struct gdphp_din *din, zval *zdata,
       din->ns = index + 1;
 
     if (din->type == GD_UNKNOWN) {
-        din->type = gdphp_get_type(*d, ctx);
+        din->type = gdphp_get_type(ZP(d), ctx);
         if (din->type == GD_UNKNOWN)
           GDPHP_DIE(ctx, "bad numeric type");
         else if (din->type == GD_NULL)
@@ -933,13 +1049,13 @@ static void gdphp_convert_array(struct gdphp_din *din, zval *zdata,
 
     /* pass 2: convert the data */
     for (zend_hash_internal_pointer_reset_ex(a, &i);
-        zend_hash_get_current_data_ex(a, (void*)&d, &i) == SUCCESS;
+        GDPHP_HASH_GET_CURRENT_DATA(d, a, i);
         zend_hash_move_forward_ex(a, &i))
     {
-      zend_hash_get_current_key_ex(a, &key, &key_len, (ulong*)&index, 0, &i);
+      GDPHP_HASH_GET_CURRENT_KEY(a, key, index, i);
 
       gdphp_to_datum(((char*)(din->data)) + index * GD_SIZE(din->type),
-          din->type, *d, 1, ctx);
+          din->type, ZP(d), 1, ctx);
     }
   }
 
@@ -1044,15 +1160,15 @@ static char *gdphp_convert_string(zval *z, struct gdphp_context_t *ctx)
 }
 
 static void gdphp_entry_complex(double *v, HashTable *a, const char *key,
-    size_t len, int partial, struct gdphp_context_t *ctx)
+    int partial, struct gdphp_context_t *ctx)
 {
-  zval **z;
+  GDPHP_ZVALP z;
 
-  dtracectx("%p, %p, \"%s\", %zu, %i", v, a, key, len, partial);
+  dtracectx("%p, %p, \"%s\", %i", v, a, key, partial);
 
-  if (zend_hash_find(a, key, len, (void**)&z) == SUCCESS) {
+  if (GDPHP_HASH_FIND(z, a, key)) {
     ctx->k = key;
-    gdphp_to_datum(v, GD_COMPLEX128, *z, 1, ctx);
+    gdphp_to_datum(v, GD_COMPLEX128, ZP(z), 1, ctx);
     ctx->k = NULL;
   } else if (!partial)
     GDPHP_DIE2(ctx, "required key '%s' not found", key);
@@ -1060,17 +1176,17 @@ static void gdphp_entry_complex(double *v, HashTable *a, const char *key,
   dreturnvoid();
 }
 
-static long gdphp_entry_long(HashTable *a, const char *key, size_t len,
-    int *missing, int partial, struct gdphp_context_t *ctx)
+static long gdphp_entry_long(HashTable *a, const char *key, int *missing,
+    int partial, struct gdphp_context_t *ctx)
 {
   long r = 0;
-  zval **z;
+  GDPHP_ZVALP z;
 
-  dtracectx("%p, \"%s\", %zu, %p, %i", a, key, len, missing, partial);
+  dtracectx("%p, \"%s\", %p, %i", a, key, missing, partial);
 
-  if (zend_hash_find(a, key, len, (void**)&z) == SUCCESS) {
+  if (GDPHP_HASH_FIND(z, a, key)) {
     ctx->k = key;
-    r = gdphp_convert_long(*z, ctx);
+    r = gdphp_convert_long(ZP(z), ctx);
     ctx->k = NULL;
     if (missing != NULL)
       *missing = 0;
@@ -1083,17 +1199,17 @@ static long gdphp_entry_long(HashTable *a, const char *key, size_t len,
   return r;
 }
 
-static double gdphp_entry_double(HashTable *a, const char *key, size_t len,
-    int partial, struct gdphp_context_t *ctx)
+static double gdphp_entry_double(HashTable *a, const char *key, int partial,
+    struct gdphp_context_t *ctx)
 {
   double r = 0;
-  zval **z;
+  GDPHP_ZVALP z;
 
-  dtracectx("%p, \"%s\", %zu, %i", a, key, len, partial);
+  dtracectx("%p, \"%s\", %i", a, key, partial);
 
-  if (zend_hash_find(a, key, len, (void**)&z) == SUCCESS) {
+  if (GDPHP_HASH_FIND(z, a, key)) {
     ctx->k = key;
-    r = gdphp_convert_double(*z, ctx);
+    r = gdphp_convert_double(ZP(z), ctx);
     ctx->k = NULL;
   } else if (!partial)
     GDPHP_DIE2(ctx, "required key '%s' not found", key);
@@ -1105,22 +1221,20 @@ static double gdphp_entry_double(HashTable *a, const char *key, size_t len,
 static int gdphp_entry_infields(char **l, HashTable *a, int min, int max,
     int partial, struct gdphp_context_t *ctx)
 {
-  zval **z;
   int n = 0;
+  GDPHP_ZVALP z;
 
   dtracectx("%p, %p, %i, %i, %i", l, a, min, max, partial);
 
-  if (zend_hash_find(a, "in_fields", sizeof("in_fields"), (void**)&z) ==
-      SUCCESS)
-  {
+  if (GDPHP_HASH_FIND(z, a, "in_fields")) {
     ctx->k = "in_fields";
-    if (Z_TYPE_PP(z) == IS_ARRAY)
-      n = gdphp_convert_nsarray(l, *z, min, max, ctx);
-    else if (Z_TYPE_PP(z) == IS_STRING) {
+    if (Z_TYPE_P(ZP(z)) == IS_ARRAY)
+      n = gdphp_convert_nsarray(l, ZP(z), min, max, ctx);
+    else if (Z_TYPE_P(ZP(z)) == IS_STRING) {
       if (min > 1)
         GDPHP_DIE(ctx, "bad string array count");
       n = 1;
-      l[0] = gdphp_convert_string(*z, ctx);
+      l[0] = gdphp_convert_string(ZP(z), ctx);
     } else
       GDPHP_DIE(ctx, "expected string or string array");
     ctx->k = NULL;
@@ -1131,24 +1245,23 @@ static int gdphp_entry_infields(char **l, HashTable *a, int min, int max,
   return n;
 }
 
-static int gdphp_entry_cmparray(double *l, HashTable *a, char *key, size_t len,
-    int min, int max, unsigned mask, int partial, struct gdphp_context_t *ctx)
+static int gdphp_entry_cmparray(double *l, HashTable *a, char *key, int min,
+    int max, unsigned mask, int partial, struct gdphp_context_t *ctx)
 {
-  zval **z;
   int n = 0;
+  GDPHP_ZVALP z;
 
-  dtracectx("%p, %p, \"%s\", %zu, %i, %i, 0x%X", l, a, key, len, min, max,
-      mask);
+  dtracectx("%p, %p, \"%s\", %i, %i, 0x%X", l, a, key, min, max, mask);
 
-  if (zend_hash_find(a, key, len, (void**)&z) == SUCCESS) {
+  if (GDPHP_HASH_FIND(z, a, key)) {
     ctx->k = key;
-    if (Z_TYPE_PP(z) == IS_ARRAY)
-      n = gdphp_convert_cmparray(l, *z, min, max, mask, ctx);
-    else if (Z_TYPE_PP(z) == IS_DOUBLE) {
+    if (Z_TYPE_P(ZP(z)) == IS_ARRAY)
+      n = gdphp_convert_cmparray(l, ZP(z), min, max, mask, ctx);
+    else if (Z_TYPE_P(ZP(z)) == IS_DOUBLE) {
       if (min > 1)
         GDPHP_DIE(ctx, "bad array count");
       n = 1;
-      l[0] = Z_DVAL_PP(z);
+      l[0] = Z_DVAL_P(ZP(z));
     } else
       GDPHP_DIE(ctx, "expected array or float");
     ctx->k = NULL;
@@ -1165,13 +1278,13 @@ static unsigned gdphp_entry_scalars(char** scalar, int *scalar_ind,
     HashTable *a, unsigned mask, struct gdphp_context_t *ctx)
 {
   unsigned mask_out = 0;
-  zval **z;
+  GDPHP_ZVALP z;
   int i;
 
   dtracectx("%p, %p, %p, 0x%X", scalar, scalar_ind, a, mask);
   
   /* find 'scalar' in the entry array */
-  if (zend_hash_find(a, "scalar", sizeof("scalar"), (void**)&z) != SUCCESS) {
+  if (!GDPHP_HASH_FIND(z, a, "scalar")) {
     dreturn("%i", 0);
     return 0;
   }
@@ -1179,45 +1292,45 @@ static unsigned gdphp_entry_scalars(char** scalar, int *scalar_ind,
   ctx->k = "scalar";
 
   /* 'scalar' must be an array (or null) */
-  if (Z_TYPE_PP(z) == IS_NULL) {
+  if (z == NULL || Z_TYPE_P(ZP(z)) == IS_NULL) {
     ctx->k = NULL;
     dreturn("%i", 0);
     return 0;
-  } else if (Z_TYPE_PP(z) != IS_ARRAY)
+  } else if (Z_TYPE_P(ZP(z)) != IS_ARRAY)
     GDPHP_DIE(ctx, "expected array");
 
   /* loop through the array of scalars */
-  a = Z_ARRVAL_PP(z);
+  a = Z_ARRVAL_P(ZP(z));
   for (i = 0; i < 2 * GD_MAX_LINCOM; ++i) {
     if (!(mask & (1 << i)))
       continue;
 
     /* get the i'th scalar array element */
     ctx->i = i;
-    if (zend_hash_index_find(a, i, (void**)&z) == SUCCESS) {
+    if (GDPHP_HASH_INDEX_FIND(z, a,i)) {
       HashTable *sa;
 
-      if (Z_TYPE_PP(z) == IS_NULL)
+      if (Z_TYPE_P(ZP(z)) == IS_NULL)
         continue;
-      if (Z_TYPE_PP(z) != IS_ARRAY)
+      if (Z_TYPE_P(ZP(z)) != IS_ARRAY)
         GDPHP_DIE(ctx, "expected array");
 
-      sa = Z_ARRVAL_PP(z);
+      sa = Z_ARRVAL_P(ZP(z));
 
       /* element zero should be the name of a scalar field. */
-      if (zend_hash_index_find(sa, 0, (void**)&z) == SUCCESS) {
-        if (Z_TYPE_PP(z) != IS_STRING)
+      if (GDPHP_HASH_INDEX_FIND(z, sa, 0)) {
+        if (Z_TYPE_P(ZP(z)) != IS_STRING)
           GDPHP_DIE(ctx, "expected scalar field name");
-        scalar[i] = Z_STRVAL_PP(z);
+        scalar[i] = Z_STRVAL_P(ZP(z));
       } else
-        GDPHP_DIE(ctx, "element zero of should be scalar field name");
+        GDPHP_DIE(ctx, "element zero should be scalar field name");
 
       mask_out |= 1 << i;
 
       /* element one should be the index; if missing zero is assumed */
-      if (zend_hash_index_find(sa, 1, (void**)&z) == SUCCESS) {
-        convert_to_long(*z); /* coerce */
-        scalar_ind[i] = Z_LVAL_PP(z);
+      if (GDPHP_HASH_INDEX_FIND(z, sa, 1)) {
+        convert_to_long(ZP(z)); /* coerce */
+        scalar_ind[i] = Z_LVAL_P(ZP(z));
       } else
         scalar_ind[i] = 0;
     }
@@ -1229,17 +1342,17 @@ static unsigned gdphp_entry_scalars(char** scalar, int *scalar_ind,
   return mask_out;
 }
 
-static char *gdphp_entry_string(HashTable *a, const char *key,
-    size_t len, int partial, struct gdphp_context_t *ctx)
+static char *gdphp_entry_string(HashTable *a, const char *key, int partial,
+    struct gdphp_context_t *ctx)
 {
   char *s = NULL;
-  zval **z;
+  GDPHP_ZVALP z;
   
-  dtracectx("%p, \"%s\", %zu, %i", a, key, len, partial);
+  dtracectx("%p, \"%s\", %i", a, key, partial);
 
-  if (zend_hash_find(a, key, len, (void**)&z) == SUCCESS) {
+  if (GDPHP_HASH_FIND(z, a, key)) {
     ctx->k = key;
-    s = gdphp_convert_string(*z, ctx);
+    s = gdphp_convert_string(ZP(z), ctx);
     ctx->k = NULL;
   } else if (!partial)
     GDPHP_DIE2(ctx, "required key '%s' not found", key);
@@ -1268,16 +1381,15 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
     memset(E, 0, sizeof(gd_entry_t));
 
   if (!partial)
-    E->field = gdphp_entry_string(a, "field", sizeof("field"), partial, ctx);
+    E->field = gdphp_entry_string(a, "field", partial, ctx);
 
-  E->field_type = gdphp_entry_long(a, "field_type", sizeof("field_type"), NULL,
-      partial, ctx);
+  E->field_type = gdphp_entry_long(a, "field_type", NULL, partial, ctx);
 
   if (no_fragment)
     E->fragment_index = 0;
   else
-    E->fragment_index = gdphp_entry_long(a, "fragment_index",
-        sizeof("fragment_index"), NULL, partial, ctx);
+    E->fragment_index = gdphp_entry_long(a, "fragment_index", NULL, partial,
+        ctx);
 
 
   switch (E->field_type) {
@@ -1288,29 +1400,27 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
       mask = gdphp_entry_scalars(E->scalar, E->scalar_ind, a, 3, ctx);
 
       if (!(mask & 1))
-        E->EN(bit,bitnum) = gdphp_entry_long(a, "bitnum", sizeof("bitnum"),
-            NULL, partial, ctx);
+        E->EN(bit,bitnum) = gdphp_entry_long(a, "bitnum", NULL, partial, ctx);
 
       if (!(mask & 2)) {
-        E->EN(bit,numbits) = gdphp_entry_long(a, "numbits", sizeof("numbits"),
-            &missing, partial, ctx);
+        E->EN(bit,numbits) = gdphp_entry_long(a, "numbits", &missing, partial,
+            ctx);
 
         if (missing && !partial)
           E->EN(bit,numbits) = 1;
       }
       break;
     case GD_CARRAY_ENTRY:
-      E->EN(scalar,array_len) = gdphp_entry_long(a, "array_len",
-          sizeof("array_len"), NULL, partial, ctx);
+      E->EN(scalar,array_len) = gdphp_entry_long(a, "array_len", NULL, partial,
+          ctx);
       /* FALLTHROUGH */
     case GD_CONST_ENTRY:
-      E->EN(scalar,const_type) = gdphp_entry_long(a, "const_type",
-          sizeof("const_type"), NULL, partial, ctx);
+      E->EN(scalar,const_type) = gdphp_entry_long(a, "const_type", NULL,
+          partial, ctx);
       break;
     case GD_LINCOM_ENTRY:
       /* honour n_fields, if given */
-      n = gdphp_entry_long(a, "n_fields", sizeof("n_fields"), &missing,
-          partial, ctx);
+      n = gdphp_entry_long(a, "n_fields", &missing, partial, ctx);
       if (missing) {
         min = 1;
         max = GD_MAX_LINCOM;
@@ -1332,31 +1442,30 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
       tmask = (1 << max) - 1;
 
       if ((mask & tmask) != tmask)
-        gdphp_entry_cmparray((double*)E->EN(lincom,cm), a, "m", sizeof("m"),
-            min, max, mask, partial, ctx);
+        gdphp_entry_cmparray((double*)E->EN(lincom,cm), a, "m", min, max, mask,
+            partial, ctx);
 
       if (((mask >> GD_MAX_LINCOM) & tmask) != tmask)
-        gdphp_entry_cmparray((double*)E->EN(lincom,cb), a, "b", sizeof("m"),
-            min, max, mask >> GD_MAX_LINCOM, partial, ctx);
+        gdphp_entry_cmparray((double*)E->EN(lincom,cb), a, "b", min, max,
+            mask >> GD_MAX_LINCOM, partial, ctx);
       else
         E->EN(lincom,n_fields) = max;
       break;
     case GD_LINTERP_ENTRY:
       gdphp_entry_infields((char**)E->in_fields, a, 1, 1, partial, ctx);
-      E->EN(linterp,table) = gdphp_entry_string(a, "table", sizeof("table"),
-          partial, ctx);
+      E->EN(linterp,table) = gdphp_entry_string(a, "table", partial, ctx);
       break;
     case GD_MPLEX_ENTRY:
       gdphp_entry_infields((char**)E->in_fields, a, 2, 2, partial, ctx);
       mask = gdphp_entry_scalars(E->scalar, E->scalar_ind, a, 3, ctx);
 
       if (!(mask & 1))
-        E->EN(mplex,count_val) = gdphp_entry_long(a, "count_val",
-            sizeof("count_val"), NULL, partial, ctx);
+        E->EN(mplex,count_val) = gdphp_entry_long(a, "count_val", NULL, partial,
+            ctx);
       
       if (!(mask & 2)) {
-        E->EN(mplex,period) = gdphp_entry_long(a, "period", sizeof("period"),
-            &missing, partial, ctx);
+        E->EN(mplex,period) = gdphp_entry_long(a, "period", &missing, partial,
+            ctx);
 
         if (missing)
           E->EN(mplex,period) = 0;
@@ -1370,13 +1479,11 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
       gdphp_entry_infields((char**)E->in_fields, a, 1, 1, partial, ctx);
       mask = gdphp_entry_scalars(E->scalar, E->scalar_ind, a, 1, ctx);
       if (!(mask & 1))
-        E->EN(phase,shift) = gdphp_entry_long(a, "shift", sizeof("shift"), NULL,
-            partial, ctx);
+        E->EN(phase,shift) = gdphp_entry_long(a, "shift", NULL, partial, ctx);
       break;
     case GD_POLYNOM_ENTRY:
       /* honour poly_ord, if given */
-      n = gdphp_entry_long(a, "poly_ord", sizeof("poly_ord"), &missing, partial,
-          ctx);
+      n = gdphp_entry_long(a, "poly_ord", &missing, partial, ctx);
       if (missing) {
         min = 2;
         max = GD_MAX_POLYORD + 1;
@@ -1394,16 +1501,15 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
       tmask = (1 << max) - 1;
       if ((mask & tmask) != tmask)
         E->EN(polynom,poly_ord) =
-          gdphp_entry_cmparray((double*)E->EN(polynom,ca), a, "a", sizeof("a"),
-            min, max, mask, partial, ctx) - 1;
+          gdphp_entry_cmparray((double*)E->EN(polynom,ca), a, "a", min, max,
+              mask, partial, ctx) - 1;
       else
         E->EN(polynom,poly_ord) = max - 1;
       break;
     case GD_RAW_ENTRY:
-      E->EN(raw,data_type) = gdphp_entry_long(a, "data_type",
-          sizeof("data_type"), NULL, partial, ctx);
-      E->EN(raw,spf) = gdphp_entry_long(a, "spf", sizeof("spf"), NULL, partial,
+      E->EN(raw,data_type) = gdphp_entry_long(a, "data_type", NULL, partial,
           ctx);
+      E->EN(raw,spf) = gdphp_entry_long(a, "spf", NULL, partial, ctx);
       break;
     case GD_RECIP_ENTRY:
       gdphp_entry_infields((char**)E->in_fields, a, 1, 1, partial, ctx);
@@ -1411,7 +1517,7 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
       E->flags |= GD_EN_COMPSCAL;
       if (!(mask & 1))
         gdphp_entry_complex((double*)gd_csp_(E->EN(recip,cdividend)), a,
-            "dividend", sizeof("dividend"), partial, ctx);
+            "dividend", partial, ctx);
       break;
     case GD_STRING_ENTRY:
       /* nothing to do */
@@ -1419,23 +1525,22 @@ static void gdphp_to_entry(gd_entry_t *E, zval *z, const gd_entry_t *old_E,
     case GD_WINDOW_ENTRY:
       gdphp_entry_infields((char**)E->in_fields, a, 2, 2, partial, ctx);
       mask = gdphp_entry_scalars(E->scalar, E->scalar_ind, a, 1, ctx);
-      E->EN(window,windop) = gdphp_entry_long(a, "windop", sizeof("windop"),
-          NULL, partial, ctx);
+      E->EN(window,windop) = gdphp_entry_long(a, "windop", NULL, partial, ctx);
       if (!(mask & 1))
         switch (E->EN(window,windop)) {
           case GD_WINDOP_EQ:
           case GD_WINDOP_NE:
-            E->EN(window,threshold.i) = gdphp_entry_long(a, "threshold",
-                sizeof("threshold"), NULL, partial, ctx);
+            E->EN(window,threshold.i) = gdphp_entry_long(a, "threshold", NULL,
+                partial, ctx);
             break;
           case GD_WINDOP_SET:
           case GD_WINDOP_CLR:
-            E->EN(window,threshold.u) = gdphp_entry_long(a, "threshold",
-                sizeof("threshold"), NULL, partial, ctx);
+            E->EN(window,threshold.u) = gdphp_entry_long(a, "threshold", NULL,
+                partial, ctx);
             break;
           default:
             E->EN(window,threshold.r) = gdphp_entry_double(a, "threshold",
-                sizeof("threshold"), partial, ctx);
+                partial, ctx);
             break;
         }
       break;
@@ -1455,7 +1560,7 @@ static zval *gdphp_to_string_array(zval *z, const char **l, int n)
   dtrace("%p, %p, %i", z, l, n);
 
   if (z == NULL)
-    ALLOC_INIT_ZVAL(z);
+    GDPHP_INIT_ZVAL(z);
 
   array_init(z);
 
@@ -1463,7 +1568,7 @@ static zval *gdphp_to_string_array(zval *z, const char **l, int n)
     if (l[i] == NULL)
       add_index_null(z, i);
     else
-      add_index_string(z, i, l[i], 1);
+      gdphp_add_index_string(z, i, l[i]);
 
   dreturn("%p", z);
   return z;
@@ -1570,14 +1675,18 @@ static void gdphp_data_to_array(zval *a, const void *data, gd_type_t type,
         add_index_double(a, i, ((double*)(data))[i]);
       break;
     case GD_COMPLEX64:
-      for (i = 0; i < n; ++i)
-        add_index_zval(a, i, gdphp_from_complex(NULL, ((float*)(data))[i * 2],
-              ((float*)(data))[i * 2 + 1]));
+      for (i = 0; i < n; ++i) {
+        GDPHP_ZVAL_NULL(tmp);
+        add_index_zval(a, i, gdphp_from_complex(RZ(tmp),
+              ((float*)(data))[i * 2], ((float*)(data))[i * 2 + 1]));
+        }
       break;
     case GD_COMPLEX128:
-      for (i = 0; i < n; ++i)
-        add_index_zval(a, i, gdphp_from_complex(NULL, ((double*)(data))[i * 2],
-              ((double*)(data))[i * 2 + 1]));
+      for (i = 0; i < n; ++i) {
+        GDPHP_ZVAL_NULL(tmp);
+        add_index_zval(a, i, gdphp_from_complex(RZ(tmp),
+              ((double*)(data))[i * 2], ((double*)(data))[i * 2 + 1]));
+      }
       break;
     default:
       /* fill with nulls */
@@ -1595,7 +1704,7 @@ static zval *gdphp_from_data(zval *z, size_t n, gd_type_t data_type, void *data,
   dtrace("%p, %zu, 0x%X, %p, %i, %i", z, n, data_type, data, duplicate, unpack);
 
   if (z == NULL)
-    ALLOC_INIT_ZVAL(z);
+    GDPHP_INIT_ZVAL(z);
 
   if (unpack) {
     array_init(z);
@@ -1607,11 +1716,8 @@ static zval *gdphp_from_data(zval *z, size_t n, gd_type_t data_type, void *data,
       if (!duplicate)
         efree(data);
       ZVAL_EMPTY_STRING(z);
-    } else {
-      if (!duplicate)
-        data = erealloc(data, n * GD_SIZE(data_type)); /* trim excess */
-      ZVAL_STRINGL(z, data, n * GD_SIZE(data_type), duplicate);
-    }
+    } else
+      GDPHP_COPY_DATA(z, data, n * GD_SIZE(data_type), duplicate);
   }
 
   dreturn("%p", z);
@@ -1620,7 +1726,7 @@ static zval *gdphp_from_data(zval *z, size_t n, gd_type_t data_type, void *data,
 
 /* convert a zval to a long, with null checking - unfortunately PHP
  * automatically converts nulls passed as longs into zero */
-static int gdphp_long_from_zval_null(zval *z, long dflt)
+static long gdphp_long_from_zval_null(zval *z, long dflt)
 {
   long v = dflt;
 
@@ -1636,9 +1742,9 @@ static int gdphp_long_from_zval_null(zval *z, long dflt)
 }
 
 /* get the unpack value */
-static zend_bool gdphp_unpack(zval *z)
+static int gdphp_unpack(zval *z)
 {
-  zend_bool unpack;
+  int unpack;
 
   dtrace("%p", z);
 
@@ -1679,10 +1785,8 @@ PHP_MINIT_FUNCTION(getdata)
   gdphp_register_constants(module_number);
 
   /* conveniences */
-  zend_register_long_constant(ZEND_STRS("GD_INT"), GDPHP_LONG, CONST_CS,
-      module_number TSRMLS_CC);
-  zend_register_long_constant(ZEND_STRS("GD_FLOAT"), GD_FLOAT64, CONST_CS,
-      module_number TSRMLS_CC);
+  GDPHP_REGISTER_LONG_CONSTANT("GD_FLOAT", GD_FLOAT64, module_number);
+  GDPHP_REGISTER_LONG_CONSTANT("GD_INT", GDPHP_LONG_TYPE, module_number);
 
   /* dirfile resource */
   le_gdphp_dirfile = zend_register_list_destructors_ex(gdphp_dirfile_dtor, NULL,
@@ -1740,8 +1844,8 @@ PHP_FUNCTION(gd_add)
 PHP_FUNCTION(gd_add_alias)
 {
   char *field_code, *target;
-  int field_code_len, target_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, target_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -1756,8 +1860,8 @@ PHP_FUNCTION(gd_add_alias)
 PHP_FUNCTION(gd_add_bit)
 {
   char *field_code, *in_field;
-  int field_code_len, in_field_len;
-  long bitnum, index = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG bitnum, index = 0;
   zval *znumbits = NULL;
 
   int numbits;
@@ -1777,8 +1881,8 @@ PHP_FUNCTION(gd_add_bit)
 PHP_FUNCTION(gd_add_carray)
 {
   char *field_code;
-  int field_code_len;
-  long data_type;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG data_type;
   zval *z1, *z2 = NULL, *z3 = NULL;
   DIRFILE *D;
 
@@ -1824,8 +1928,8 @@ PHP_FUNCTION(gd_add_carray)
 PHP_FUNCTION(gd_add_const)
 {
   char *field_code;
-  int field_code_len;
-  long data_type, index = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG data_type, index = 0;
   zval *z;
 
   DIRFILE *D;
@@ -1846,8 +1950,8 @@ PHP_FUNCTION(gd_add_const)
 PHP_FUNCTION(gd_add_divide)
 {
   char *field_code, *in1, *in2;
-  int field_code_len, in1_len, in2_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, in1_len, in2_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -1862,8 +1966,8 @@ PHP_FUNCTION(gd_add_divide)
 PHP_FUNCTION(gd_add_lincom)
 {
   char *field_code;
-  int field_code_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG index = 0;
   zval *zin, *zm, *zb;
 
   char *in[GD_MAX_LINCOM];
@@ -1893,8 +1997,8 @@ PHP_FUNCTION(gd_add_lincom)
 PHP_FUNCTION(gd_add_linterp)
 {
   char *field_code, *in_field, *table;
-  int field_code_len, in_field_len, table_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, in_field_len, table_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -1909,8 +2013,8 @@ PHP_FUNCTION(gd_add_linterp)
 PHP_FUNCTION(gd_add_mplex)
 {
   char *field_code, *in1, *in2;
-  int field_code_len, in1_len, in2_len;
-  long count, period = 0, index = 0;
+  GDPHP_SLEN field_code_len, in1_len, in2_len;
+  GDPHP_LONG count, period = 0, index = 0;
 
   DIRFILE *D;
 
@@ -1926,8 +2030,8 @@ PHP_FUNCTION(gd_add_mplex)
 PHP_FUNCTION(gd_add_multiply)
 {
   char *field_code, *in1, *in2;
-  int field_code_len, in1_len, in2_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, in1_len, in2_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -1942,8 +2046,8 @@ PHP_FUNCTION(gd_add_multiply)
 PHP_FUNCTION(gd_add_phase)
 {
   char *field_code, *in_field;
-  int field_code_len, in_field_len;
-  long shift, index = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG shift, index = 0;
 
   DIRFILE *D;
 
@@ -1958,8 +2062,8 @@ PHP_FUNCTION(gd_add_phase)
 PHP_FUNCTION(gd_add_polynom)
 {
   char *field_code, *in_field;
-  int field_code_len, in_field_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG index = 0;
   zval *za;
 
   double a[2 * (GD_MAX_POLYORD + 1)];
@@ -1983,8 +2087,8 @@ PHP_FUNCTION(gd_add_polynom)
 PHP_FUNCTION(gd_add_raw)
 {
   char *field_code;
-  int field_code_len;
-  long data_type, spf, index = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG data_type, spf, index = 0;
 
   DIRFILE *D;
 
@@ -1999,9 +2103,9 @@ PHP_FUNCTION(gd_add_raw)
 PHP_FUNCTION(gd_add_recip)
 {
   char *field_code, *in_field;
-  int field_code_len, in_field_len;
+  GDPHP_SLEN field_code_len, in_field_len;
   zval *zdividend;
-  long index = 0;
+  GDPHP_LONG index = 0;
 
   double dividend[2];
   DIRFILE *D;
@@ -2020,8 +2124,8 @@ PHP_FUNCTION(gd_add_recip)
 PHP_FUNCTION(gd_add_sbit)
 {
   char *field_code, *in_field;
-  int field_code_len, in_field_len;
-  long bitnum, index = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG bitnum, index = 0;
   zval *znumbits = NULL;
 
   int numbits;
@@ -2041,8 +2145,8 @@ PHP_FUNCTION(gd_add_sbit)
 PHP_FUNCTION(gd_add_spec)
 {
   char *spec;
-  int spec_len;
-  long index = 0;
+  GDPHP_SLEN spec_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -2056,8 +2160,8 @@ PHP_FUNCTION(gd_add_spec)
 PHP_FUNCTION(gd_add_string)
 {
   char *field_code, *value;
-  int field_code_len, value_len;
-  long index = 0;
+  GDPHP_SLEN field_code_len, value_len;
+  GDPHP_LONG index = 0;
 
   DIRFILE *D;
 
@@ -2072,8 +2176,8 @@ PHP_FUNCTION(gd_add_string)
 PHP_FUNCTION(gd_add_window)
 {
   char *field_code, *in1, *in2;
-  int field_code_len, in1_len, in2_len;
-  long windop, index = 0;
+  GDPHP_SLEN field_code_len, in1_len, in2_len;
+  GDPHP_LONG windop, index = 0;
   zval *zthreshold;
 
   gd_triplet_t threshold;
@@ -2094,7 +2198,7 @@ PHP_FUNCTION(gd_add_window)
 PHP_FUNCTION(gd_alias_target)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char *s;
@@ -2109,13 +2213,13 @@ PHP_FUNCTION(gd_alias_target)
     GDPHP_RETURN_F;
 
   dreturn("\"%s\"", s);
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_aliases)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char **fl;
@@ -2137,7 +2241,7 @@ PHP_FUNCTION(gd_aliases)
 PHP_FUNCTION(gd_alter_affixes)
 {
   zval *zprefix, *zsuffix;
-  long index;
+  GDPHP_LONG index;
   
   char *prefix = NULL, *suffix = NULL;
   DIRFILE *D;
@@ -2162,8 +2266,8 @@ PHP_FUNCTION(gd_alter_affixes)
 PHP_FUNCTION(gd_alter_bit)
 {
   char *field_code, *in_field = NULL;
-  int field_code_len, in_field_len;
-  long numbits = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG numbits = 0;
   zval *zbitnum = NULL;
 
   DIRFILE *D;
@@ -2185,8 +2289,8 @@ PHP_FUNCTION(gd_alter_bit)
 PHP_FUNCTION(gd_alter_carray)
 {
   char *field_code;
-  int field_code_len;
-  long type = GD_NULL, len = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG type = GD_NULL, len = 0;
 
   DIRFILE *D;
 
@@ -2200,8 +2304,8 @@ PHP_FUNCTION(gd_alter_carray)
 PHP_FUNCTION(gd_alter_const)
 {
   char *field_code;
-  int field_code_len;
-  long type = GD_NULL;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG type = GD_NULL;
 
   DIRFILE *D;
 
@@ -2214,7 +2318,7 @@ PHP_FUNCTION(gd_alter_const)
 
 PHP_FUNCTION(gd_alter_encoding)
 {
-  long e, i;
+  GDPHP_LONG e, i;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -2228,7 +2332,7 @@ PHP_FUNCTION(gd_alter_encoding)
 
 PHP_FUNCTION(gd_alter_endianness)
 {
-  long e, i;
+  GDPHP_LONG e, i;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -2243,7 +2347,7 @@ PHP_FUNCTION(gd_alter_endianness)
 PHP_FUNCTION(gd_alter_entry)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
   zend_bool recode = 0;
   zval *z;
 
@@ -2268,7 +2372,7 @@ PHP_FUNCTION(gd_alter_entry)
 
 PHP_FUNCTION(gd_alter_frameoffset)
 {
-  long i, o;
+  GDPHP_LONG i, o;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -2283,7 +2387,7 @@ PHP_FUNCTION(gd_alter_frameoffset)
 PHP_FUNCTION(gd_alter_divide)
 {
   char *field_code, *in_field1 = NULL, *in_field2 = NULL;
-  int field_code_len, in_field1_len, in_field2_len;
+  GDPHP_SLEN field_code_len, in_field1_len, in_field2_len;
   
   DIRFILE *D;
   char *in_field1p, *in_field2p;
@@ -2302,8 +2406,8 @@ PHP_FUNCTION(gd_alter_divide)
 PHP_FUNCTION(gd_alter_lincom)
 {
   char *field_code;
-  int field_code_len;
-  long n = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG n = 0;
   zval *zin = NULL, *zm = NULL, *zb = NULL;
 
   DIRFILE *D;
@@ -2368,7 +2472,7 @@ PHP_FUNCTION(gd_alter_lincom)
 PHP_FUNCTION(gd_alter_linterp)
 {
   char *field_code, *in_field = NULL, *table = NULL;
-  int field_code_len, in_field_len, table_len;
+  GDPHP_SLEN field_code_len, in_field_len, table_len;
   zend_bool rename = 0;
   
   DIRFILE *D;
@@ -2388,7 +2492,7 @@ PHP_FUNCTION(gd_alter_linterp)
 PHP_FUNCTION(gd_alter_mplex)
 {
   char *field_code, *in_field1 = NULL, *in_field2 = NULL;
-  int field_code_len, in_field1_len, in_field2_len;
+  GDPHP_SLEN field_code_len, in_field1_len, in_field2_len;
   zval *zcount_val = NULL, *zperiod = NULL;
   
   DIRFILE *D;
@@ -2423,7 +2527,7 @@ PHP_FUNCTION(gd_alter_mplex)
 PHP_FUNCTION(gd_alter_multiply)
 {
   char *field_code, *in_field1 = NULL, *in_field2 = NULL;
-  int field_code_len, in_field1_len, in_field2_len;
+  GDPHP_SLEN field_code_len, in_field1_len, in_field2_len;
   
   DIRFILE *D;
   char *in_field1p, *in_field2p;
@@ -2442,7 +2546,7 @@ PHP_FUNCTION(gd_alter_multiply)
 PHP_FUNCTION(gd_alter_phase)
 {
   char *field_code, *in_field = NULL;
-  int field_code_len, in_field_len;
+  GDPHP_SLEN field_code_len, in_field_len;
   zval *zshift = NULL;
   
   DIRFILE *D;
@@ -2476,8 +2580,8 @@ PHP_FUNCTION(gd_alter_phase)
 PHP_FUNCTION(gd_alter_polynom)
 {
   char *field_code, *in_field = NULL;
-  int field_code_len, in_field_len;
-  long o = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG o = 0;
   zval *za = NULL;
 
   DIRFILE *D;
@@ -2515,7 +2619,7 @@ PHP_FUNCTION(gd_alter_polynom)
 
 PHP_FUNCTION(gd_alter_protection)
 {
-  long p, i;
+  GDPHP_LONG p, i;
 
   DIRFILE *D;
 
@@ -2529,8 +2633,8 @@ PHP_FUNCTION(gd_alter_protection)
 PHP_FUNCTION(gd_alter_raw)
 {
   char *field_code;
-  int field_code_len;
-  long type = GD_NULL, spf = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG type = GD_NULL, spf = 0;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -2545,7 +2649,7 @@ PHP_FUNCTION(gd_alter_raw)
 PHP_FUNCTION(gd_alter_recip)
 {
   char *field_code, *in_field = NULL;
-  int field_code_len, in_field_len;
+  GDPHP_SLEN field_code_len, in_field_len;
   zval *zdividend = NULL;
 
   DIRFILE *D;
@@ -2571,8 +2675,8 @@ PHP_FUNCTION(gd_alter_recip)
 PHP_FUNCTION(gd_alter_sbit)
 {
   char *field_code, *in_field = NULL;
-  int field_code_len, in_field_len;
-  long numbits = 0;
+  GDPHP_SLEN field_code_len, in_field_len;
+  GDPHP_LONG numbits = 0;
   zval *zbitnum = NULL;
 
   DIRFILE *D;
@@ -2594,7 +2698,7 @@ PHP_FUNCTION(gd_alter_sbit)
 PHP_FUNCTION(gd_alter_spec)
 {
   char *spec;
-  int spec_len;
+  GDPHP_SLEN spec_len;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -2609,8 +2713,8 @@ PHP_FUNCTION(gd_alter_spec)
 PHP_FUNCTION(gd_alter_window)
 {
   char *field_code, *in1 = NULL, *in2 = NULL;
-  int field_code_len, in1_len, in2_len;
-  long windop;
+  GDPHP_SLEN field_code_len, in1_len, in2_len;
+  GDPHP_LONG windop = GD_WINDOP_UNK;
   zval *zthreshold = NULL;
 
   gd_triplet_t threshold;
@@ -2643,7 +2747,7 @@ PHP_FUNCTION(gd_alter_window)
 PHP_FUNCTION(gd_bof)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   long bof;
@@ -2664,7 +2768,7 @@ PHP_FUNCTION(gd_bof)
 PHP_FUNCTION(gd_carray_len)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   size_t n;
@@ -2688,7 +2792,7 @@ PHP_FUNCTION(gd_carray_len)
 PHP_FUNCTION(gd_array_len)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   size_t n;
@@ -2709,7 +2813,8 @@ PHP_FUNCTION(gd_array_len)
 PHP_FUNCTION(gd_carrays)
 {
   zval *zunpack = NULL;
-  long data_type;
+  GDPHP_LONG data_type;
+  GDPHP_ZVAL_NULL(tmp);
 
   DIRFILE *D;
   int unpack, i;
@@ -2730,7 +2835,7 @@ PHP_FUNCTION(gd_carrays)
   array_init(return_value);
 
   for (i = 0; c[i].n; ++i)
-    add_index_zval(return_value, i, gdphp_from_data(NULL, c[i].n, data_type,
+    add_index_zval(return_value, i, gdphp_from_data(RZ(tmp), c[i].n, data_type,
           c[i].d, 1, unpack));
 
   dreturnvoid();
@@ -2752,7 +2857,7 @@ PHP_FUNCTION(gd_close)
 
     /* delete the resource on success */
     r->D = NULL; /* avoid double close */
-    zend_list_delete(Z_LVAL_P(z));
+    gdphp_list_close(z);
   }
 
   GDPHP_RETURN_T;
@@ -2760,7 +2865,7 @@ PHP_FUNCTION(gd_close)
 
 PHP_FUNCTION(gd_constants)
 {
-  long data_type;
+  GDPHP_LONG data_type;
   zval *zunpack = NULL;
 
   void *data;
@@ -2791,8 +2896,8 @@ PHP_FUNCTION(gd_constants)
 PHP_FUNCTION(gd_delete)
 {
   char *field_code;
-  int field_code_len;
-  long flags = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG flags = 0;
 
   DIRFILE *D;
 
@@ -2805,7 +2910,7 @@ PHP_FUNCTION(gd_delete)
 
 PHP_FUNCTION(gd_desync)
 {
-  long flags = 0;
+  GDPHP_LONG flags = 0;
 
   int r;
   DIRFILE *D;
@@ -2855,7 +2960,7 @@ PHP_FUNCTION(gd_dirfilekey)
   GDPHP_FETCH_DIRFILE(r, z);
 
   dreturn("\"%s\"", r->key);
-  RETURN_STRINGL(r->key, r->key_len, 1);
+  GDPHP_RET_STRL_COPY(r->key, r->key_len);
 }
 
 PHP_FUNCTION(gd_dirfilename)
@@ -2869,7 +2974,7 @@ PHP_FUNCTION(gd_dirfilename)
 
   s = gd_dirfilename(D);
   dreturn("\"%s\"", s);
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_discard)
@@ -2888,7 +2993,7 @@ PHP_FUNCTION(gd_discard)
 
     /* delete the resource on success */
     r->D = NULL; /* avoid double close */
-    zend_list_delete(Z_LVAL_P(z));
+    gdphp_list_close(z);
   }
 
   GDPHP_RETURN_T;
@@ -2896,7 +3001,7 @@ PHP_FUNCTION(gd_discard)
 
 PHP_FUNCTION(gd_encoding)
 {
-  long i = 0;
+  GDPHP_LONG i = 0;
 
   DIRFILE *D;
 
@@ -2915,7 +3020,7 @@ PHP_FUNCTION(gd_encoding)
 
 PHP_FUNCTION(gd_endianness)
 {
-  long i = 0;
+  GDPHP_LONG i = 0;
 
   DIRFILE *D;
 
@@ -2935,7 +3040,7 @@ PHP_FUNCTION(gd_endianness)
 PHP_FUNCTION(gd_entry)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   gd_entry_t E;
@@ -2955,8 +3060,8 @@ PHP_FUNCTION(gd_entry)
 PHP_FUNCTION(gd_entry_list)
 {
   char *parent;
-  int parent_len;
-  long type = 0, flags = 0;
+  GDPHP_SLEN parent_len;
+  GDPHP_LONG type = 0, flags = 0;
   DIRFILE *D;
 
   const char **fl;
@@ -2980,7 +3085,7 @@ PHP_FUNCTION(gd_entry_list)
 PHP_FUNCTION(gd_entry_type)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   gd_entype_t entype;
@@ -3001,7 +3106,7 @@ PHP_FUNCTION(gd_entry_type)
 PHP_FUNCTION(gd_eof)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   long eof;
@@ -3046,7 +3151,7 @@ PHP_FUNCTION(gd_error_string)
   s = gd_error_string(D, NULL, 0);
 
   if (s) {
-    RETVAL_STRING(s, 1);
+    GDPHP_RETVAL_STRING(s);
     dreturn("\"%s\"", s);
     free(s);
   } else
@@ -3076,7 +3181,7 @@ PHP_FUNCTION(gd_field_list_by_type)
 {
   DIRFILE *D;
   const char **fl;
-  long type;
+  GDPHP_LONG type;
 
   dtracephp();
 
@@ -3094,7 +3199,7 @@ PHP_FUNCTION(gd_field_list_by_type)
 
 PHP_FUNCTION(gd_flags)
 {
-  long set = 0, reset = 0;
+  GDPHP_LONG set = 0, reset = 0;
   unsigned long flags;
 
   DIRFILE *D;
@@ -3112,7 +3217,7 @@ PHP_FUNCTION(gd_flags)
 PHP_FUNCTION(gd_flush)
 {
   char *field_code = NULL;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   char *field_codep;
   DIRFILE *D;
@@ -3128,7 +3233,7 @@ PHP_FUNCTION(gd_flush)
 
 PHP_FUNCTION(gd_fragment_affixes)
 {
-  long index;
+  GDPHP_LONG index;
 
   DIRFILE *D;
   char *affixes[2] = {NULL, NULL};
@@ -3149,7 +3254,7 @@ PHP_FUNCTION(gd_fragment_affixes)
 PHP_FUNCTION(gd_fragment_index)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   int i;
@@ -3169,7 +3274,7 @@ PHP_FUNCTION(gd_fragment_index)
 
 PHP_FUNCTION(gd_fragmentname)
 {
-  long i;
+  GDPHP_LONG i;
   const char *s;
 
   DIRFILE *D;
@@ -3181,12 +3286,12 @@ PHP_FUNCTION(gd_fragmentname)
   s = gd_fragmentname(D, i);
 
   dreturn("\"%s\"", s);
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_frameoffset)
 {
-  long i = 0;
+  GDPHP_LONG i = 0;
   
   DIRFILE *D;
 
@@ -3203,9 +3308,9 @@ PHP_FUNCTION(gd_frameoffset)
 PHP_FUNCTION(gd_framenum)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
   double value;
-  long start = 0, stop = 0;
+  GDPHP_LONG start = 0, stop = 0;
 
   DIRFILE *D;
 
@@ -3225,10 +3330,10 @@ PHP_FUNCTION(gd_framenum)
 
 PHP_FUNCTION(gd_get_carray)
 {
-  long data_type;
+  GDPHP_LONG data_type;
   char *field_code;
-  int field_code_len;
-  long start = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG start = 0;
   zval *zlen = NULL, *zunpack = NULL;
 
   long len;
@@ -3282,9 +3387,9 @@ PHP_FUNCTION(gd_get_carray)
 
 PHP_FUNCTION(gd_get_constant)
 {
-  long data_type;
+  GDPHP_LONG data_type;
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   char datum[16];
   DIRFILE *D;
@@ -3306,9 +3411,15 @@ PHP_FUNCTION(gd_get_constant)
 PHP_FUNCTION(gd_get_string)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
+#if ZEND_MODULE_API_NO >= 20151012
+  zend_string *s;
+#else
   char *s;
+#endif
+  char *p;
+
   size_t len;
   DIRFILE *D;
 
@@ -3327,24 +3438,40 @@ PHP_FUNCTION(gd_get_string)
   }
 
   /* allocate a buffer and get the string */
-  s = emalloc(len);
+#if ZEND_MODULE_API_NO >= 20151012
+  s = zend_string_alloc(len - 1, 0);
+  p = ZSTR_VAL(s);
+#else
+  p = s = emalloc(len);
+#endif
+
+  if (gd_get_string(D, field_code, len, p) != len) {
+#if ZEND_MODULE_API_NO >= 20151012
+    zend_string_release(s);
+#else
+    efree(s);
+#endif
 
-  if (gd_get_string(D, field_code, len, s) != len)
     GDPHP_RETURN_F;
+  }
 
-  dreturn("\"%s\"", s);
+  dreturn("\"%s\"", p);
+#if ZEND_MODULE_API_NO >= 20151012
+  RETURN_STR(s);
+#else
   RETURN_STRINGL(s, len - 1, 0);
+#endif
 }
 
 PHP_FUNCTION(gd_getdata)
 {
-  long first_frame, first_sample, num_frames, num_samples;
+  GDPHP_LONG first_frame, first_sample, num_frames, num_samples;
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
   size_t ns;
   zval *zunpack = NULL;
 
-  long data_type = GD_UNKNOWN;
+  GDPHP_LONG data_type = GD_UNKNOWN;
   DIRFILE *D;
   zend_bool unpack;
   size_t n = 0;
@@ -3387,7 +3514,10 @@ PHP_FUNCTION(gd_getdata)
     n = gd_getdata(D, field_code, first_frame, first_sample, 0, ns, data_type,
         data);
 
-    GDPHP_CHECK_ERROR(D);
+    if (gd_error(D)) {
+      efree(data);
+      GDPHP_RETURN_F;
+    }
 
     gdphp_from_data(return_value, n, data_type, data, 0, unpack);
 
@@ -3398,7 +3528,7 @@ PHP_FUNCTION(gd_getdata)
 PHP_FUNCTION(gd_hidden)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   int hidden;
@@ -3420,7 +3550,7 @@ PHP_FUNCTION(gd_hidden)
 PHP_FUNCTION(gd_hide)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
 
@@ -3434,8 +3564,8 @@ PHP_FUNCTION(gd_hide)
 PHP_FUNCTION(gd_include)
 {
   char *path, *prefix = NULL, *suffix = NULL;
-  int path_len, prefix_len, suffix_len;
-  long i, parent, flags = 0;
+  GDPHP_SLEN path_len, prefix_len, suffix_len;
+  GDPHP_LONG i, parent, flags = 0;
 
   DIRFILE *D;
 
@@ -3470,14 +3600,14 @@ PHP_FUNCTION(gd_invalid_dirfile)
   r->D = gd_invalid_dirfile();
   r->persist = 0;
 
-  ZEND_REGISTER_RESOURCE(return_value, r, le_gdphp_dirfile);
+  GDPHP_RET_RES(r, le_gdphp_dirfile);
   dreturn("%p", r);
 }
 
 PHP_FUNCTION(gd_linterp_tablename)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char *s;
@@ -3490,13 +3620,13 @@ PHP_FUNCTION(gd_linterp_tablename)
     GDPHP_RETURN_F;
 
   dreturn("\"%s\"", s);
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_madd)
 {
   char *parent;
-  int parent_len;
+  GDPHP_SLEN parent_len;
   zval *z;
 
   gd_entry_t E;
@@ -3518,7 +3648,7 @@ PHP_FUNCTION(gd_madd)
 PHP_FUNCTION(gd_madd_alias)
 {
   char *field_code, *target, *parent;
-  int field_code_len, target_len, parent_len;
+  GDPHP_SLEN field_code_len, target_len, parent_len;
 
   DIRFILE *D;
 
@@ -3533,15 +3663,19 @@ PHP_FUNCTION(gd_madd_alias)
 PHP_FUNCTION(gd_madd_bit)
 {
   char *field_code, *in_field, *parent;
-  int field_code_len, in_field_len, parent_len;
-  long bitnum, numbits = 1;
+  GDPHP_SLEN field_code_len, in_field_len, parent_len;
+  GDPHP_LONG bitnum;
+  long numbits;
+  zval *znumbits;
 
   DIRFILE *D;
 
   dtracephp();
 
-  GDPHP_PARSED("sssl|l", &parent, &parent_len, &field_code, &field_code_len,
-      &in_field, &in_field_len, &bitnum, &numbits);
+  GDPHP_PARSED("sssl|z", &parent, &parent_len, &field_code, &field_code_len,
+      &in_field, &in_field_len, &bitnum, &znumbits);
+
+  numbits = gdphp_long_from_zval_null(znumbits, 1);
 
   GDPHP_RETURN_BOOL(gd_madd_bit(D, parent, field_code, in_field, bitnum,
         numbits));
@@ -3550,8 +3684,8 @@ PHP_FUNCTION(gd_madd_bit)
 PHP_FUNCTION(gd_madd_carray)
 {
   char *field_code, *parent;
-  int field_code_len, parent_len;
-  long data_type;
+  GDPHP_SLEN field_code_len, parent_len;
+  GDPHP_LONG data_type;
   zval *zdata1, *zdata2 = NULL;
   DIRFILE *D;
 
@@ -3577,8 +3711,8 @@ PHP_FUNCTION(gd_madd_carray)
 PHP_FUNCTION(gd_madd_const)
 {
   char *field_code, *parent;
-  int field_code_len, parent_len;
-  long data_type;
+  GDPHP_SLEN field_code_len, parent_len;
+  GDPHP_LONG data_type;
   zval *z;
 
   DIRFILE *D;
@@ -3600,7 +3734,7 @@ PHP_FUNCTION(gd_madd_const)
 PHP_FUNCTION(gd_madd_divide)
 {
   char *field_code, *in1, *in2, *parent;
-  int field_code_len, in1_len, in2_len, parent_len;
+  GDPHP_SLEN field_code_len, in1_len, in2_len, parent_len;
 
   DIRFILE *D;
 
@@ -3615,7 +3749,7 @@ PHP_FUNCTION(gd_madd_divide)
 PHP_FUNCTION(gd_madd_lincom)
 {
   char *field_code, *parent;
-  int field_code_len, parent_len;
+  GDPHP_SLEN field_code_len, parent_len;
   zval *zin, *zm, *zb;
 
   char *in[GD_MAX_LINCOM];
@@ -3646,7 +3780,7 @@ PHP_FUNCTION(gd_madd_lincom)
 PHP_FUNCTION(gd_madd_linterp)
 {
   char *field_code, *in_field, *table, *parent;
-  int field_code_len, in_field_len, table_len, parent_len;
+  GDPHP_SLEN field_code_len, in_field_len, table_len, parent_len;
 
   DIRFILE *D;
 
@@ -3661,8 +3795,8 @@ PHP_FUNCTION(gd_madd_linterp)
 PHP_FUNCTION(gd_madd_mplex)
 {
   char *field_code, *in1, *in2, *parent;
-  int field_code_len, in1_len, in2_len, parent_len;
-  long count, period = 0;
+  GDPHP_SLEN field_code_len, in1_len, in2_len, parent_len;
+  GDPHP_LONG count, period = 0;
 
   DIRFILE *D;
 
@@ -3678,7 +3812,7 @@ PHP_FUNCTION(gd_madd_mplex)
 PHP_FUNCTION(gd_madd_multiply)
 {
   char *field_code, *in1, *in2, *parent;
-  int field_code_len, in1_len, in2_len, parent_len;
+  GDPHP_SLEN field_code_len, in1_len, in2_len, parent_len;
 
   DIRFILE *D;
 
@@ -3693,8 +3827,8 @@ PHP_FUNCTION(gd_madd_multiply)
 PHP_FUNCTION(gd_madd_phase)
 {
   char *field_code, *in_field, *parent;
-  int field_code_len, in_field_len, parent_len;
-  long shift;
+  GDPHP_SLEN field_code_len, in_field_len, parent_len;
+  GDPHP_LONG shift;
 
   DIRFILE *D;
 
@@ -3709,7 +3843,7 @@ PHP_FUNCTION(gd_madd_phase)
 PHP_FUNCTION(gd_madd_polynom)
 {
   char *field_code, *in_field, *parent;
-  int field_code_len, in_field_len, parent_len;
+  GDPHP_SLEN field_code_len, in_field_len, parent_len;
   zval *za;
 
   double a[2 * (GD_MAX_POLYORD + 1)];
@@ -3733,7 +3867,7 @@ PHP_FUNCTION(gd_madd_polynom)
 PHP_FUNCTION(gd_madd_recip)
 {
   char *field_code, *in_field, *parent;
-  int field_code_len, in_field_len, parent_len;
+  GDPHP_SLEN field_code_len, in_field_len, parent_len;
   zval *zdividend;
 
   double dividend[2];
@@ -3754,15 +3888,19 @@ PHP_FUNCTION(gd_madd_recip)
 PHP_FUNCTION(gd_madd_sbit)
 {
   char *field_code, *in_field, *parent;
-  int field_code_len, in_field_len, parent_len;
-  long bitnum, numbits = 1;
+  GDPHP_SLEN field_code_len, in_field_len, parent_len;
+  GDPHP_LONG bitnum;
+  long numbits;
+  zval *znumbits;
 
   DIRFILE *D;
 
   dtracephp();
 
-  GDPHP_PARSED("sssll", &parent, &parent_len, &field_code, &field_code_len,
-      &in_field, &in_field_len, &bitnum, &numbits);
+  GDPHP_PARSED("sssl|z", &parent, &parent_len, &field_code, &field_code_len,
+      &in_field, &in_field_len, &bitnum, &znumbits);
+
+  numbits = gdphp_long_from_zval_null(znumbits, 1);
 
   GDPHP_RETURN_BOOL(gd_madd_sbit(D, parent, field_code, in_field, bitnum,
         numbits));
@@ -3771,7 +3909,7 @@ PHP_FUNCTION(gd_madd_sbit)
 PHP_FUNCTION(gd_madd_spec)
 {
   char *spec, *parent;
-  int spec_len, parent_len;
+  GDPHP_SLEN spec_len, parent_len;
 
   DIRFILE *D;
 
@@ -3785,7 +3923,7 @@ PHP_FUNCTION(gd_madd_spec)
 PHP_FUNCTION(gd_madd_string)
 {
   char *field_code, *value, *parent;
-  int field_code_len, value_len, parent_len;
+  GDPHP_SLEN field_code_len, value_len, parent_len;
 
   DIRFILE *D;
 
@@ -3800,8 +3938,8 @@ PHP_FUNCTION(gd_madd_string)
 PHP_FUNCTION(gd_madd_window)
 {
   char *field_code, *in1, *in2, *parent;
-  int field_code_len, in1_len, in2_len, parent_len;
-  long windop;
+  GDPHP_SLEN field_code_len, in1_len, in2_len, parent_len;
+  GDPHP_LONG windop;
   zval *zthreshold;
 
   gd_triplet_t threshold;
@@ -3822,7 +3960,7 @@ PHP_FUNCTION(gd_madd_window)
 PHP_FUNCTION(gd_malter_spec)
 {
   char *spec, *parent;
-  int spec_len, parent_len;
+  GDPHP_SLEN spec_len, parent_len;
   zend_bool recode = 0;
 
   DIRFILE *D;
@@ -3837,9 +3975,10 @@ PHP_FUNCTION(gd_malter_spec)
 PHP_FUNCTION(gd_mcarrays)
 {
   char *parent;
-  int parent_len;
+  GDPHP_SLEN parent_len;
   zval *zunpack = NULL;
-  long data_type;
+  GDPHP_LONG data_type;
+  GDPHP_ZVAL_NULL(tmp);
 
   DIRFILE *D;
   int unpack, i;
@@ -3860,7 +3999,7 @@ PHP_FUNCTION(gd_mcarrays)
   array_init(return_value);
 
   for (i = 0; c[i].n; ++i)
-    add_index_zval(return_value, i, gdphp_from_data(NULL, c[i].n, data_type,
+    add_index_zval(return_value, i, gdphp_from_data(RZ(tmp), c[i].n, data_type,
           c[i].d, 1, unpack));
 
   dreturnvoid();
@@ -3869,8 +4008,8 @@ PHP_FUNCTION(gd_mcarrays)
 PHP_FUNCTION(gd_mconstants)
 {
   char *parent;
-  int parent_len;
-  long data_type;
+  GDPHP_SLEN parent_len;
+  GDPHP_LONG data_type;
   zval *zunpack = NULL;
 
   void *data;
@@ -3912,7 +4051,7 @@ PHP_FUNCTION(gd_metaflush)
 PHP_FUNCTION(gd_mfield_list)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char **fl;
@@ -3933,9 +4072,9 @@ PHP_FUNCTION(gd_mfield_list)
 
 PHP_FUNCTION(gd_mfield_list_by_type)
 {
-  long type;
+  GDPHP_LONG type;
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char **fl;
@@ -3957,9 +4096,9 @@ PHP_FUNCTION(gd_mfield_list_by_type)
 PHP_FUNCTION(gd_move)
 {
   char *field_code;
-  int field_code_len;
-  long new_fragment;
-  long flags = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG new_fragment;
+  GDPHP_LONG flags = 0;
 
   DIRFILE *D;
 
@@ -3972,7 +4111,7 @@ PHP_FUNCTION(gd_move)
 
 PHP_FUNCTION(gd_mplex_lookback)
 {
-  long lookback;
+  GDPHP_LONG lookback;
 
   DIRFILE *D;
 
@@ -3988,7 +4127,7 @@ PHP_FUNCTION(gd_mplex_lookback)
 PHP_FUNCTION(gd_mstrings)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char **l;
@@ -4010,7 +4149,7 @@ PHP_FUNCTION(gd_mstrings)
 PHP_FUNCTION(gd_mvector_list)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char **fl;
@@ -4032,7 +4171,7 @@ PHP_FUNCTION(gd_mvector_list)
 PHP_FUNCTION(gd_naliases)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   long n;
   DIRFILE *D;
@@ -4053,7 +4192,7 @@ PHP_FUNCTION(gd_naliases)
 PHP_FUNCTION(gd_native_type)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   gd_type_t t;
@@ -4074,8 +4213,8 @@ PHP_FUNCTION(gd_native_type)
 PHP_FUNCTION(gd_nentries)
 {
   char *parent;
-  int parent_len;
-  long n, type = 0, flags = 0;
+  GDPHP_SLEN parent_len;
+  GDPHP_LONG n, type = 0, flags = 0;
   DIRFILE *D;
 
   char *parentp;
@@ -4112,7 +4251,7 @@ PHP_FUNCTION(gd_nfields)
 
 PHP_FUNCTION(gd_nfields_by_type)
 {
-  long n, type;
+  GDPHP_LONG n, type;
   DIRFILE *D;
 
   dtracephp();
@@ -4164,7 +4303,7 @@ PHP_FUNCTION(gd_nframes)
 PHP_FUNCTION(gd_nmfields)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   long n;
   DIRFILE *D;
@@ -4184,9 +4323,9 @@ PHP_FUNCTION(gd_nmfields)
 PHP_FUNCTION(gd_nmfields_by_type)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
-  long n, type;
+  GDPHP_LONG n, type;
   DIRFILE *D;
 
   dtracephp();
@@ -4204,7 +4343,7 @@ PHP_FUNCTION(gd_nmfields_by_type)
 PHP_FUNCTION(gd_nmvectors)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   long n;
   DIRFILE *D;
@@ -4240,31 +4379,31 @@ PHP_FUNCTION(gd_nvectors)
 
 PHP_FUNCTION(gd_open)
 {
-  long flags = GD_RDONLY;
+  GDPHP_LONG flags = GD_RDONLY;
   char *dirfilename;
-  int len;
+  GDPHP_SLEN len;
   gdphp_dirfile *r;
   char *callback = NULL;
-  int callback_len = -1;
-  zval **callback_data = NULL;
+  GDPHP_SLEN callback_len = -1;
+  GDPHP_ZVALP callback_data = NULL;
 
   dtracephp();
 
   /* parse input */
-  GDPHP_PARSE("s|lsZ", &dirfilename, &len, &flags, &callback, &callback_len,
-      &callback_data);
+  GDPHP_PARSE("s|ls" ZPP_Z, &dirfilename, &len, &flags, &callback,
+      &callback_len, &callback_data);
 
-  r = gdphp_open(dirfilename, len, flags, callback, callback_len, callback_data,
-      0);
+  r = gdphp_open(dirfilename, len, flags, callback, callback_len,
+      callback_data, 0);
 
   /* return */
-  ZEND_REGISTER_RESOURCE(return_value, r, le_gdphp_dirfile);
+  GDPHP_RET_RES(r, le_gdphp_dirfile);
   dreturn("%p", r);
 }
 
 PHP_FUNCTION(gd_parent_fragment)
 {
-  long i;
+  GDPHP_LONG i;
 
   DIRFILE *D;
 
@@ -4283,47 +4422,44 @@ PHP_FUNCTION(gd_parent_fragment)
 
 PHP_FUNCTION(gd_popen)
 {
-  long flags = GD_RDONLY;
+  GDPHP_LONG flags = GD_RDONLY;
   char *dirfilename;
-  int len;
+  GDPHP_SLEN len;
   gdphp_dirfile *r;
-  zend_rsrc_list_entry *le, new_le;
+  GDPHP_RESOURCE *le, new_le;
   char *callback = NULL;
-  int callback_len;
-  zval **callback_data = NULL;
+  GDPHP_SLEN callback_len;
+  GDPHP_ZVALP callback_data = NULL;
 
   dtracephp();
 
   /* parse input */
-  GDPHP_PARSE("s|lsz", &dirfilename, &len, &flags, &callback, &callback_len,
-      &callback_data);
+  GDPHP_PARSE("s|ls" ZPP_Z, &dirfilename, &len, &flags, &callback,
+      &callback_len, &callback_data);
 
   /* look for an existing dirfile */
-  if (zend_hash_find(&EG(persistent_list), dirfilename, len, (void**)&le)
-      == SUCCESS)
-  {
-    ZEND_REGISTER_RESOURCE(return_value, le->ptr, le_gdphp_dirfile_persist);
+  if (GDPHP_FIND_RES(le, &EG(persistent_list), dirfilename, len)) {
+    GDPHP_RET_RES(le->ptr, le_gdphp_dirfile_persist);
     dreturn("%p", le->ptr);
     return;
   }
 
   /* nope, open */
-  r = gdphp_open(dirfilename, len, flags, callback, callback_len, callback_data,
-      1);
+  r = gdphp_open(dirfilename, len, flags, callback, callback_len,
+      callback_data, 1);
 
   /* register and store */
-  ZEND_REGISTER_RESOURCE(return_value, r, le_gdphp_dirfile_persist);
+  GDPHP_RET_RES(r, le_gdphp_dirfile_persist);
   new_le.ptr = r;
   new_le.type = le_gdphp_dirfile_persist;
-  zend_hash_add(&EG(persistent_list), dirfilename, len, &new_le,
-      sizeof(zend_rsrc_list_entry), NULL);
+  GDPHP_HASH_ADD(&EG(persistent_list), dirfilename, len, new_le);
 
   dreturn("%p", r);
 }
 
 PHP_FUNCTION(gd_protection)
 {
-  long i;
+  GDPHP_LONG i;
 
   DIRFILE *D;
 
@@ -4343,7 +4479,7 @@ PHP_FUNCTION(gd_protection)
 PHP_FUNCTION(gd_put_carray)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
   zval *z1, *z2 = NULL, *z3 = NULL;
 
   DIRFILE *D;
@@ -4392,7 +4528,7 @@ PHP_FUNCTION(gd_put_carray)
 PHP_FUNCTION(gd_put_constant)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
   zval *z;
 
   DIRFILE *D;
@@ -4412,7 +4548,7 @@ PHP_FUNCTION(gd_put_constant)
 PHP_FUNCTION(gd_put_string)
 {
   char *field_code, *value;
-  int field_code_len, value_len;
+  GDPHP_SLEN field_code_len, value_len;
 
   DIRFILE *D;
 
@@ -4427,8 +4563,8 @@ PHP_FUNCTION(gd_put_string)
 PHP_FUNCTION(gd_putdata)
 {
   char *field_code;
-  int field_code_len;
-  long first_frame, first_sample;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG first_frame, first_sample;
   zval *zdata1, *zdata2 = NULL;
   DIRFILE *D;
   size_t n;
@@ -4457,7 +4593,7 @@ PHP_FUNCTION(gd_putdata)
 PHP_FUNCTION(gd_raw_close)
 {
   char *field_code = NULL;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   char *field_codep;
   DIRFILE *D;
@@ -4474,7 +4610,7 @@ PHP_FUNCTION(gd_raw_close)
 PHP_FUNCTION(gd_raw_filename)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char *s;
@@ -4487,13 +4623,13 @@ PHP_FUNCTION(gd_raw_filename)
     GDPHP_RETURN_F;
 
   dreturn("\"%s\"", s);
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_reference)
 {
   const char *field_code = NULL;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   const char *s;
@@ -4509,14 +4645,14 @@ PHP_FUNCTION(gd_reference)
   if (s == NULL)
     RETURN_NULL();
 
-  RETURN_STRING(s, 1);
+  GDPHP_RET_STR_COPY(s);
 }
 
 PHP_FUNCTION(gd_rename)
 {
   const char *old_code, *new_name;
-  int old_code_len, new_name_len;
-  long flags = 0;
+  GDPHP_SLEN old_code_len, new_name_len;
+  GDPHP_LONG flags = 0;
 
   DIRFILE *D;
 
@@ -4548,8 +4684,8 @@ PHP_FUNCTION(gd_rewrite_fragment)
 PHP_FUNCTION(gd_seek)
 {
   char *field_code;
-  int field_code_len;
-  long frame_num, sample_num, flags = 0;
+  GDPHP_SLEN field_code_len;
+  GDPHP_LONG frame_num, sample_num, flags = 0;
 
   DIRFILE *D;
   long pos;
@@ -4571,7 +4707,7 @@ PHP_FUNCTION(gd_seek)
 PHP_FUNCTION(gd_spf)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   unsigned spf;
@@ -4611,7 +4747,8 @@ PHP_FUNCTION(gd_strings)
 PHP_FUNCTION(gd_strtok)
 {
   char *s, *p;
-  int slen, i = 0;
+  GDPHP_SLEN slen;
+  int i = 0;
   
   DIRFILE *D;
 
@@ -4622,7 +4759,7 @@ PHP_FUNCTION(gd_strtok)
   array_init(return_value);
 
   for (p = gd_strtok(D, s); p; p = gd_strtok(D, NULL)) {
-    add_index_string(return_value, i++, p, 1);
+    gdphp_add_index_string(return_value, i++, p);
     free(p);
   }
 
@@ -4633,7 +4770,7 @@ PHP_FUNCTION(gd_strtok)
 PHP_FUNCTION(gd_sync)
 {
   char *field_code = NULL;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   char *field_codep;
   DIRFILE *D;
@@ -4650,7 +4787,7 @@ PHP_FUNCTION(gd_sync)
 PHP_FUNCTION(gd_tell)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
   long pos;
@@ -4671,7 +4808,7 @@ PHP_FUNCTION(gd_tell)
 PHP_FUNCTION(gd_unhide)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
 
@@ -4685,7 +4822,7 @@ PHP_FUNCTION(gd_unhide)
 PHP_FUNCTION(gd_uninclude)
 {
   DIRFILE *D;
-  long i;
+  GDPHP_LONG i;
   zend_bool del = 0;
 
   dtracephp();
@@ -4698,7 +4835,7 @@ PHP_FUNCTION(gd_uninclude)
 PHP_FUNCTION(gd_validate)
 {
   char *field_code;
-  int field_code_len;
+  GDPHP_SLEN field_code_len;
 
   DIRFILE *D;
 
@@ -4731,7 +4868,7 @@ PHP_FUNCTION(gd_vector_list)
 PHP_FUNCTION(gd_verbose_prefix)
 {
   char *prefix = NULL;
-  int prefix_len;
+  GDPHP_SLEN prefix_len;
 
   char *prefixp;
   DIRFILE *D;
@@ -4747,7 +4884,7 @@ PHP_FUNCTION(gd_verbose_prefix)
 
 PHP_FUNCTION(gd_encoding_support)
 {
-  unsigned long e;
+  GDPHP_LONG e;
   long r;
 
   dtracephp();
@@ -4763,7 +4900,6 @@ PHP_FUNCTION(gd_encoding_support)
   RETURN_LONG(r);
 }
 
-
 /* MODULE DECLARATIONS */
 static const zend_function_entry getdata_functions[] = {
   PHP_FE(gd_add, NULL)
diff --git a/bindings/php/php_getdata.h b/bindings/php/php_getdata.h
index a442161..379836e 100644
--- a/bindings/php/php_getdata.h
+++ b/bindings/php/php_getdata.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013, 2014 D. V. Wiebe
+/* Copyright (C) 2013, 2014, 2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -59,6 +59,21 @@ extern zend_module_entry getdata_module_entry;
 #define ZEND_FE_END { NULL, NULL, NULL, 0, 0 }
 #endif
 
+/* These expand to: string, length(string) where length() either includes
+ * (ZEND_STRS) or omits (ZEND_STRL) the trailing NUL.
+ */
+#if ZEND_MODULE_API_NO >= 20151012
+/* PHP7 */
+#define GDPHP_STR ZEND_STRL
+#else
+/* PHP5 */
+#define GDPHP_STR ZEND_STRS
+#endif
+
+#define GDPHP_REGISTER_LONG_CONSTANT(name,value,module_number) \
+  zend_register_long_constant(GDPHP_STR(name), value, \
+      CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC)
+
 void gdphp_register_constants(int module_number);
 
 #endif
diff --git a/bindings/php/test/Makefile.in b/bindings/php/test/Makefile.in
index 85ac0d0..da00896 100644
--- a/bindings/php/test/Makefile.in
+++ b/bindings/php/test/Makefile.in
@@ -286,6 +286,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -335,6 +336,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/bindings/php/test/callback.php b/bindings/php/test/callback.php
index 5c04e85..444da2b 100644
--- a/bindings/php/test/callback.php
+++ b/bindings/php/test/callback.php
@@ -28,7 +28,10 @@ function callback($pdata, $extra)
 
   $ret = 0;
 
-  if ($extra != 'extra stuff') {
+  if (!isset($extra)) {
+    echo "extra is unset\n";
+    $ret = 1;
+  } else if ($extra != 'extra stuff') {
     echo 'extra = ', $extra, "\n";
     $ret = 1;
   }
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
index 75f520c..7d9c4a6 100644
--- a/bindings/python/Makefile.am
+++ b/bindings/python/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2009, 2013, 2014 D. V. Wiebe
+# Copyright (C) 2009, 2013, 2014, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -22,17 +22,22 @@ AUTOMAKE_OPTIONS = foreign
 
 SUBDIRS=test
 
-nodist_python_SCRIPTS = pygetdata.so
+if MAKE_PYGETDATA_CAPI
+PYGETDATA_H=pygetdata.h
+endif
+
+nodist_python_SCRIPTS = pygetdata${PYTHON_OBJECT_SUFFIX}
+python_HEADERS = ${PYGETDATA_H}
 
 BUILT_SOURCES = pyconstants.c
 
-EXTRA_DIST = pydirfile.c pygetdata.c pyentry.c pygetdata.h pyfragment.c
+EXTRA_DIST = pydirfile.c pygetdata.c pyentry.c gdpy_intern.h pyfragment.c
 
 distutils_path=build/lib.${PYTHON_PLATFORM}-${PYTHON_VERSION}
-pygetdata.so: ${distutils_path}/pygetdata.so
+pygetdata${PYTHON_OBJECT_SUFFIX}: ${distutils_path}/pygetdata${PYTHON_OBJECT_SUFFIX}
 	cp $< $@
 
-${distutils_path}/pygetdata.so: setup.py ${BUILT_SOURCES} ${EXTRA_DIST}
+${distutils_path}/pygetdata${PYTHON_OBJECT_SUFFIX}: setup.py ${BUILT_SOURCES} ${EXTRA_DIST}
 	${PYTHON} setup.py build
 
 pyconstants.c: ../make_parameters
@@ -45,7 +50,7 @@ clean-local:
 if MAKE_PYBINDINGS
 	test ! -f setup.py || ${PYTHON} setup.py clean
 endif
-	rm -rf build pygetdata.so ${BUILT_SOURCES} debug.c *~ 
+	rm -rf build pygetdata${PYTHON_OBJECT_SUFFIX} ${BUILT_SOURCES} debug.c *~ 
 
 # Avoid a race condition from distclean deleting setup.py between the test and
 # the ${PYTHON} in the clean-local rule.  The variable shennanigans here are to
diff --git a/bindings/python/Makefile.in b/bindings/python/Makefile.in
index 3ae8db2..bc60350 100644
--- a/bindings/python/Makefile.in
+++ b/bindings/python/Makefile.in
@@ -14,6 +14,7 @@
 
 @SET_MAKE@
 
+
 VPATH = @srcdir@
 am__is_gnu_make = { \
   if test -z '$(MAKELEVEL)'; then \
@@ -101,7 +102,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
 	$(top_srcdir)/m4/version.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__python_HEADERS_DIST) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/gd_config.h \
 	$(top_builddir)/src/getdata.h
@@ -134,7 +136,7 @@ am__uninstall_files_from_dir = { \
     || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
-am__installdirs = "$(DESTDIR)$(pythondir)"
+am__installdirs = "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)"
 SCRIPTS = $(nodist_python_SCRIPTS)
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -163,6 +165,8 @@ am__can_run_installinfo = \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
+am__python_HEADERS_DIST = pygetdata.h
+HEADERS = $(python_HEADERS)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
 am__recursive_targets = \
@@ -354,6 +358,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -403,6 +408,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -444,7 +450,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2009, 2013, 2014 D. V. Wiebe
+# Copyright (C) 2009, 2013, 2014, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -466,9 +472,11 @@ top_srcdir = @top_srcdir@
 #
 AUTOMAKE_OPTIONS = foreign
 SUBDIRS = test
-nodist_python_SCRIPTS = pygetdata.so
+ at MAKE_PYGETDATA_CAPI_TRUE@PYGETDATA_H = pygetdata.h
+nodist_python_SCRIPTS = pygetdata${PYTHON_OBJECT_SUFFIX}
+python_HEADERS = ${PYGETDATA_H}
 BUILT_SOURCES = pyconstants.c
-EXTRA_DIST = pydirfile.c pygetdata.c pyentry.c pygetdata.h pyfragment.c
+EXTRA_DIST = pydirfile.c pygetdata.c pyentry.c gdpy_intern.h pyfragment.c
 distutils_path = build/lib.${PYTHON_PLATFORM}-${PYTHON_VERSION}
 
 # Avoid a race condition from distclean deleting setup.py between the test and
@@ -554,6 +562,27 @@ mostlyclean-libtool:
 
 clean-libtool:
 	-rm -rf .libs _libs
+install-pythonHEADERS: $(python_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(python_HEADERS)'; test -n "$(pythondir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pythondir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pythondir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pythondir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(pythondir)" || exit $$?; \
+	done
+
+uninstall-pythonHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(python_HEADERS)'; test -n "$(pythondir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir)
 
 # This directory's subdirectories are mostly independent; you can cd
 # into them and run 'make' without going through this Makefile.
@@ -712,10 +741,10 @@ distdir: $(DISTFILES)
 check-am: all-am
 check: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) check-recursive
-all-am: Makefile $(SCRIPTS)
+all-am: Makefile $(SCRIPTS) $(HEADERS)
 installdirs: installdirs-recursive
 installdirs-am:
-	for dir in "$(DESTDIR)$(pythondir)"; do \
+	for dir in "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: $(BUILT_SOURCES)
@@ -770,7 +799,7 @@ info: info-recursive
 
 info-am:
 
-install-data-am: install-nodist_pythonSCRIPTS
+install-data-am: install-nodist_pythonSCRIPTS install-pythonHEADERS
 
 install-dvi: install-dvi-recursive
 
@@ -814,7 +843,7 @@ ps: ps-recursive
 
 ps-am:
 
-uninstall-am: uninstall-nodist_pythonSCRIPTS
+uninstall-am: uninstall-nodist_pythonSCRIPTS uninstall-pythonHEADERS
 
 .MAKE: $(am__recursive_targets) all check install install-am \
 	install-strip
@@ -828,18 +857,19 @@ uninstall-am: uninstall-nodist_pythonSCRIPTS
 	install-exec-am install-html install-html-am install-info \
 	install-info-am install-man install-nodist_pythonSCRIPTS \
 	install-pdf install-pdf-am install-ps install-ps-am \
-	install-strip installcheck installcheck-am installdirs \
-	installdirs-am maintainer-clean maintainer-clean-generic \
-	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-	ps ps-am tags tags-am uninstall uninstall-am \
-	uninstall-nodist_pythonSCRIPTS
+	install-pythonHEADERS install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-nodist_pythonSCRIPTS \
+	uninstall-pythonHEADERS
 
 .PRECIOUS: Makefile
 
-pygetdata.so: ${distutils_path}/pygetdata.so
+pygetdata${PYTHON_OBJECT_SUFFIX}: ${distutils_path}/pygetdata${PYTHON_OBJECT_SUFFIX}
 	cp $< $@
 
-${distutils_path}/pygetdata.so: setup.py ${BUILT_SOURCES} ${EXTRA_DIST}
+${distutils_path}/pygetdata${PYTHON_OBJECT_SUFFIX}: setup.py ${BUILT_SOURCES} ${EXTRA_DIST}
 	${PYTHON} setup.py build
 
 pyconstants.c: ../make_parameters
@@ -850,7 +880,7 @@ pyconstants.c: ../make_parameters
 
 clean-local:
 @MAKE_PYBINDINGS_TRUE@	test ! -f setup.py || ${PYTHON} setup.py clean
-	rm -rf build pygetdata.so ${BUILT_SOURCES} debug.c *~ 
+	rm -rf build pygetdata${PYTHON_OBJECT_SUFFIX} ${BUILT_SOURCES} debug.c *~ 
 $(gd_distclean_generic): clean-local
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/bindings/python/pygetdata.h b/bindings/python/gdpy_intern.h
similarity index 52%
copy from bindings/python/pygetdata.h
copy to bindings/python/gdpy_intern.h
index d3d66ac..5093b86 100644
--- a/bindings/python/pygetdata.h
+++ b/bindings/python/gdpy_intern.h
@@ -18,18 +18,21 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include <Python.h>
+#include "../../src/internal.h"
 
+/* Deal with pyconfig.h */
+#undef _XOPEN_SOURCE
 #undef _BSD_SOURCE
-#undef _POSIX_SOURCE
 #undef _SVID_SOURCE
 #undef _POSIX_C_SOURCE
-#undef SIZEOF_OFF_T
-#include "../../src/internal.h"
 
-#ifdef HAVE_NUMPY_ARRAYOBJECT_H
-# define PY_ARRAY_UNIQUE_SYMBOL gdpy_array_api
-# include <numpy/arrayobject.h>
+#include <Python.h>
+
+#ifdef GDPY_INCLUDE_NUMPY
+# ifdef HAVE_NUMPY_ARRAYOBJECT_H
+#  define PY_ARRAY_UNIQUE_SYMBOL gdpy_array_api
+#  include <numpy/arrayobject.h>
+# endif
 #endif
 
 #define GDPY_UNSIGNED        0x00
@@ -42,6 +45,12 @@
 #define GDPY_FLOAT           0x20
 #define GDPY_PYCOMPLEX       0x40
 
+#if HAVE_PYCAPSULE_NEW
+#define PYGETDATA_MODULE
+#include "pygetdata.h"
+#define PYGETDATA_CAPI
+#endif
+
 #define GDPY_INT_AS_LONG        (GDPY_INT       | GDPY_SIGNED)
 #define GDPY_LONG_AS_ULL        (GDPY_LONG      | GDPY_UNSIGNED)
 #define GDPY_LONG_AS_SLL        (GDPY_LONG      | GDPY_SIGNED)
@@ -49,6 +58,19 @@
 #define GDPY_FLOAT_AS_DOUBLE    (GDPY_FLOAT     | GDPY_IEEE754)
 #define GDPY_COMPLEX_AS_COMPLEX (GDPY_PYCOMPLEX | GDPY_COMPLEX)
 
+#ifndef HAVE_PYERR_NEWEXCEPTIONWITHDOC
+#define PyErr_NewExceptionWithDoc(a,b,c,d) PyErr_NewException(a,c,d)
+#endif
+
+/* Python3 does away with Int objects */
+#if PY_MAJOR_VERSION < 3
+#define gdpyint_fromlong PyInt_FromLong
+#define gdpyint_check(o) (PyInt_Check(o) || PyLong_Check(o))
+#else
+#define gdpyint_fromlong PyLong_FromLong
+#define gdpyint_check PyLong_Check
+#endif
+
 #define GDPY_INVALID_OP(t) ( \
     t != GD_WINDOP_EQ && t != GD_WINDOP_NE && \
     t != GD_WINDOP_GE && t != GD_WINDOP_GT && \
@@ -63,30 +85,17 @@
     t != GD_FLOAT32   && t != GD_FLOAT64 && \
     t != GD_COMPLEX64 && t != GD_COMPLEX128 )
 
-#define PYGD_CHECK_ERROR(D,R) PYGD_CHECK_ERROR2(D,R,)
+#define GDPY_CHECK_ERROR(D,R,ce) GDPY_CHECK_ERROR2(D,R,,ce)
 
-#define PYGD_CHECK_ERROR2(D,R,E) \
+#define GDPY_CHECK_ERROR2(D,R,E,ce) \
   do { \
-    int e; \
-    if ((e = gd_error(D))) { \
-      PYGD_REPORT_ERROR(D,e); \
+    if (gdpy_report_error(D,ce)) { \
       E; \
       dreturnvoid(); \
       return (R); \
     } \
   } while(0)
 
-#define PYGD_REPORT_ERROR(D,e) \
-  do { \
-    char *buffer = gd_error_string((D), NULL, 0); \
-    if (buffer) { \
-      PyErr_SetString(gdpy_exceptions[e], buffer); \
-      free(buffer); \
-    } else \
-      PyErr_SetString(gdpy_exceptions[e], "Unspecified error"); \
-  } while (0)
-
-
 extern PyObject *gdpy_exceptions[GD_N_ERROR_CODES];
 extern PyTypeObject gdpy_dirfile;
 extern PyTypeObject gdpy_entry;
@@ -105,11 +114,13 @@ struct gdpy_dirfile_t {
   PyObject *callback_data;
   PyObject *callback;
   int callback_exception;
+  char *char_enc;
 };
 
 struct gdpy_entry_t {
   PyObject_HEAD
   gd_entry_t *E;
+  char *char_enc;
 };
 
 struct gdpy_fragment_t {
@@ -133,13 +144,76 @@ union gdpy_quadruple_value {
 #define gdpy_from_complexp(c) PyComplex_FromDoubles((c)[0], (c)[1])
 #define gdpy_from_complex(c) PyComplex_FromDoubles(creal(c), cimag(c))
 
-extern int gdpylist_append(PyObject *, PyObject *);
+/* Deal with PyString, PyBytes, PyUnicode changes between Python2 and 3 */
+#if PY_MAJOR_VERSION < 3
+
+/* Check for an encoded string pyobj */
+#  define gdpy_encobj_check PyString_Check
+
+/* Convert to a "native" Python string object
+ * (ie. PyString in Python2 and PyUnicode in Python3) */
+#  define gdpystrobj_from_string PyString_FromString
+
+/* For already-encoded python input strings */
+#  define gdpy_string_from_encobj PyString_AsString
+
+/* For non-decoded returned strings */
+#  define gdpy_encobj_from_string PyString_FromString
+#else
+#  define gdpy_encobj_check PyBytes_Check
+#  define gdpystrobj_from_string PyUnicode_FromString
+#  define gdpy_string_from_encobj PyBytes_AsString
+#  define gdpy_encobj_from_string PyBytes_FromString
+#endif
+
+/* Python3 changes to the modinit */
+#if PY_MAJOR_VERSION < 3
+#define GDPY_MODINITFUNC PyMODINIT_FUNC initpygetdata(void)
+#define GDPY_MODINITSUCCESS return
+#define GDPY_MODINITFAILURE return
+#else
+#define GDPY_MODINITFUNC PyMODINIT_FUNC PyInit_pygetdata(void)
+#define GDPY_MODINITSUCCESS return gdpy_mod
+#define GDPY_MODINITFAILURE return NULL
+#endif
+
+/* Python3 compatibility */
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+
+/* Handle filesystem encoding */
+#if PY_MAJOR_VERSION < 3
+#define gdpy_path_from_pyobj(o,c) gdpy_string_from_pyobj(o,c,NULL)
+#define gdpyobj_from_path PyString_FromString
+#else
+extern char *gdpy_path_from_pyobj_(PyObject*, int);
+#define gdpy_path_from_pyobj(o,c,d) gdpy_path_from_pyobj_(o,d)
+#define gdpyobj_from_path PyUnicode_DecodeFSDefault
+#endif
+
+/* Declarations for the CAPI */
+#ifdef PYGETDATA_CAPI
+extern DIRFILE *gdpy_dirfile_dirfile(struct gdpy_dirfile_t *);
+extern int gdpy_dirfile_raise(struct gdpy_dirfile_t *);
+#endif
+
+extern int gdpy_report_error(DIRFILE*, char*);
+extern char *gdpy_copy_global_charenc(void);
+extern PyObject *gdpyobj_from_string(const char*, const char*);
+extern PyObject *gdpyobj_from_estring(const char*, const char*);
+extern PyObject *gdpy_charenc_obj(const char*);
+extern int gdpy_parse_charenc(char**, PyObject*);
+extern long gdpy_long_from_pyobj(PyObject*);
+extern unsigned long gdpy_ulong_from_pyobj(PyObject*);
+extern char *gdpy_string_from_pyobj(PyObject*, const char*, const char*);
+extern int gdpylist_append(PyObject*, PyObject*);
 extern int gdpy_convert_from_pyobj(PyObject*, union gdpy_quadruple_value*,
     gd_type_t);
+extern int gdpy_coerce_from_pyobj(PyObject*, gd_type_t, void*);
 extern gd_type_t gdpy_convert_from_pylist(PyObject*, void*, gd_type_t, size_t);
-extern PyObject *gdpy_convert_to_pyobj(const void*, gd_type_t);
+extern PyObject *gdpy_convert_to_pyobj(const void*, gd_type_t, int);
 extern PyObject *gdpy_convert_to_pylist(const void*, gd_type_t, size_t);
-extern PyObject *gdpy_to_pystringlist(const char **list);
 extern int gdpy_npytype_from_type(gd_type_t type);
 extern gd_type_t gdpy_type_from_npytype(int npytype);
 PyMODINIT_FUNC initpygetdata(void);
diff --git a/bindings/python/pydirfile.c b/bindings/python/pydirfile.c
index aea2e31..7352b12 100644
--- a/bindings/python/pydirfile.c
+++ b/bindings/python/pydirfile.c
@@ -19,7 +19,62 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #define NO_IMPORT_ARRAY
-#include "pygetdata.h"
+#define GDPY_INCLUDE_NUMPY
+#include "gdpy_intern.h"
+
+/* Create an array of strings from a NULL-terminated string list */
+static PyObject *gdpyobj_from_strarr(const char **list,
+    const char *char_enc)
+{
+  PyObject *pyobj;
+  size_t i;
+
+  dtrace("%p, %p", list, char_enc);
+
+  pyobj = PyList_New(0);
+  if (pyobj)
+    for (i = 0; list[i] != NULL; ++i) {
+      PyObject *str = gdpyobj_from_string(list[i], char_enc);
+      if (str == NULL) {
+        Py_DECREF(pyobj);
+        pyobj = NULL;
+        break;
+      }
+
+      if (gdpylist_append(pyobj, str)) {
+        Py_DECREF(pyobj);
+        pyobj = NULL;
+        break;
+      }
+    }
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+#ifdef PYGETDATA_CAPI
+/* Dirfile CAPI */
+DIRFILE *gdpy_dirfile_dirfile(struct gdpy_dirfile_t *self)
+{
+  dtrace("%p", self);
+
+  dreturn("%p", self->D);
+  return self->D;
+}
+
+int gdpy_dirfile_raise(struct gdpy_dirfile_t *self)
+{
+  dtrace("%p", self);
+
+  if (gdpy_report_error(self->D, self->char_enc)) {
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  dreturn("%i", 0);
+  return 0;
+}
+#endif
 
 /* Dirfile */
 static int gdpy_callback_func(gd_parser_data_t *pdata, void *extra)
@@ -68,7 +123,7 @@ static int gdpy_callback_func(gd_parser_data_t *pdata, void *extra)
           self->callback_exception = 1;
           break;
         case 1:
-          r = (int)PyInt_AsLong(PyTuple_GetItem(result, 0));
+          r = (int)gdpy_long_from_pyobj(PyTuple_GetItem(result, 0));
 
           if (PyErr_Occurred()) {
             self->callback_exception = 1;
@@ -76,14 +131,17 @@ static int gdpy_callback_func(gd_parser_data_t *pdata, void *extra)
           }
           break;
         default:
-          r = (int)PyInt_AsLong(PyTuple_GetItem(result, 0));
+          r = (int)gdpy_long_from_pyobj(PyTuple_GetItem(result, 0));
 
           if (PyErr_Occurred()) {
             self->callback_exception = 1;
             r = GD_SYNTAX_ABORT;
           }
 
-          new_string = PyString_AsString(PyTuple_GetItem(result, 1));
+          /* new_string will be free'd by GetData */
+          new_string = gdpy_string_from_pyobj(PyTuple_GetItem(result, 1),
+              self->char_enc,
+              "Element two of tuple returned from callback must be string");
 
           if (new_string == NULL) {
             self->callback_exception = 1;
@@ -92,11 +150,9 @@ static int gdpy_callback_func(gd_parser_data_t *pdata, void *extra)
 
           pdata->line = new_string;
       }
-
-      if (PyTuple_Size(result) == 1) {
-      }
-    } else if (PyString_Check(result)) {
-      new_string = PyString_AsString(result);
+    } else if (gdpy_encobj_check(result) || PyUnicode_Check(result)) {
+      /* new_string will be free'd by GetData */
+      new_string = gdpy_string_from_pyobj(result, self->char_enc, NULL);
 
       if (new_string == NULL) {
         self->callback_exception = 1;
@@ -105,8 +161,8 @@ static int gdpy_callback_func(gd_parser_data_t *pdata, void *extra)
 
       r = GD_SYNTAX_RESCAN;
       pdata->line = new_string;
-    } else if (PyInt_Check(result))
-      r = (int)PyInt_AsLong(result);
+    } else if (gdpyint_check(result))
+      r = (int)gdpy_long_from_pyobj(result);
     else {
       PyErr_SetString(PyExc_TypeError,
           "bad return type from callback function");
@@ -126,6 +182,7 @@ static void gdpy_dirfile_delete(struct gdpy_dirfile_t *self)
   free(self->verbose_prefix);
   Py_XDECREF(self->callback);
   Py_XDECREF(self->callback_data);
+  free(self->char_enc);
   PyObject_Del(self);
 
   dreturnvoid();
@@ -146,6 +203,7 @@ static PyObject *gdpy_dirfile_create(PyTypeObject *type, PyObject *args,
     self->verbose_prefix = NULL;
     self->callback = NULL;
     self->callback_data = NULL;
+    self->char_enc = gdpy_copy_global_charenc();
   }
 
   dreturn("%p", self);
@@ -157,31 +215,42 @@ static int gdpy_dirfile_init(struct gdpy_dirfile_t *self, PyObject *args,
 {
   PyObject *pycallback = NULL;
   PyObject *pycallback_data = Py_None;
-  char *keywords[] = {"name", "flags", "callback", "extra", NULL};
+  PyObject *char_enc = NULL;
+  char *keywords[] = {"name", "flags", "callback", "extra",
+    "character_encoding", NULL};
   PyObject *name = NULL;
   unsigned long flags = GD_RDONLY;
+  char *dirfilename;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "|OkOO:pygetdata.dirfile.__init__", keywords, &name, &flags,
-        &pycallback, &pycallback_data))
+        "|OkOOO:pygetdata.dirfile.__init__", keywords, &name, &flags,
+        &pycallback, &pycallback_data, &char_enc))
   {
     dreturn("%i", -1);
     return -1;
   }
 
+  /* First, try to update character_encoding, if requested */
+  if (char_enc) {
+    if (gdpy_parse_charenc(&self->char_enc, char_enc)) {
+      dreturn("%i", -1);
+      return -1;
+    }
+  }
+
   /* An invalid dirfile was requested */
   if (name == NULL || name == Py_None) {
     self->D = gd_invalid_dirfile();
 
-    PYGD_CHECK_ERROR(self->D, -1);
+    GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
     dreturn("%i", 0);
     return 0;
   }
 
-  if (!PyString_Check(name)) {
+  if (!gdpy_encobj_check(name) && !PyUnicode_Check(name)) {
     PyErr_SetString(PyExc_TypeError, "name must be a string or None");
     dreturn("%i", -1);
     return -1;
@@ -201,15 +270,24 @@ static int gdpy_dirfile_init(struct gdpy_dirfile_t *self, PyObject *args,
   self->callback_data = pycallback_data;
   self->callback_exception = 0;
 
-  self->D = gd_cbopen(PyString_AsString(name), (unsigned int)flags,
+  dirfilename = gdpy_path_from_pyobj(name, self->char_enc);
+
+  if (dirfilename == NULL) {
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  self->D = gd_cbopen(dirfilename, (unsigned int)flags,
       (pycallback == NULL) ? NULL : gdpy_callback_func, self);
 
+  free(dirfilename);
+
   if (self->callback_exception) {
     dreturn("%i", -1);
     return -1;
   }
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -232,7 +310,7 @@ static PyObject *gdpy_dirfile_add(struct gdpy_dirfile_t *self,
 
   gd_add(self->D, entry->E);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -243,21 +321,23 @@ static PyObject *gdpy_dirfile_addspec(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "spec", "fragment_index", NULL };
-  const char *spec;
+  char *spec;
   int fragment = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s|i:pygetdata.dirfile.add_spec",
-        keywords, &spec, &fragment))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "et|i:pygetdata.dirfile.add_spec", keywords, self->char_enc, &spec,
+        &fragment))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_add_spec(self->D, spec, fragment);
+  PyMem_Free(spec);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -274,16 +354,17 @@ static PyObject *gdpy_dirfile_alter(struct gdpy_dirfile_t *self,
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "sO!|i:pygetdata.dirfile.alter",
-        keywords, &field_code, &gdpy_entry, &entry, &recode))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "etO!|i:pygetdata.dirfile.alter",
+        keywords, self->char_enc, &field_code, &gdpy_entry, &entry, &recode))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_alter_entry(self->D, field_code, entry->E, recode);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -294,21 +375,23 @@ static PyObject *gdpy_dirfile_alterspec(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "spec", "recode", NULL };
-  const char *spec;
+  char *spec;
   int recode = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|i:pygetdata.dirfile.alter_spec", keywords, &spec, &recode))
+        "et|i:pygetdata.dirfile.alter_spec", keywords, self->char_enc, &spec,
+        &recode))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_alter_spec(self->D, spec, recode);
+  PyMem_Free(spec);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -320,7 +403,7 @@ static PyObject *gdpy_dirfile_close(struct gdpy_dirfile_t *self)
   dtrace("%p", self);
 
   if (gd_close(self->D))
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   self->D = gd_invalid_dirfile();
 
@@ -333,21 +416,22 @@ static PyObject *gdpy_dirfile_delentry(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"field_code", "flags", NULL};
-  const char *field_code;
+  char *field_code;
   unsigned int flags = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|I:pygetdata.dirfile.delete", keywords, &field_code, &flags))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et|I:pygetdata.dirfile.delete",
+        keywords, self->char_enc, &field_code, &flags))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_delete(self->D, field_code, flags);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -359,7 +443,7 @@ static PyObject *gdpy_dirfile_discard(struct gdpy_dirfile_t *self)
   dtrace("%p", self);
 
   if (gd_discard(self->D)) {
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
   }
 
   /* Here we replace D with an empty, invalid dirfile object.  */
@@ -375,7 +459,7 @@ static PyObject *gdpy_dirfile_getcarray(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = {"field_code", "return_type", "start", "len", "as_list",
     NULL};
-  const char *field_code;
+  char *field_code;
   unsigned int start = 0;
   unsigned PY_LONG_LONG len = 0;
   int as_list = 0;
@@ -387,8 +471,8 @@ static PyObject *gdpy_dirfile_getcarray(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|OIKi:pygetdata.dirfile.get_carray", keywords, &field_code,
-        &return_type_obj, &start, &len, &as_list))
+        "et|OIKi:pygetdata.dirfile.get_carray", keywords, self->char_enc,
+        &field_code, &return_type_obj, &start, &len, &as_list))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -396,16 +480,18 @@ static PyObject *gdpy_dirfile_getcarray(struct gdpy_dirfile_t *self,
 
   /* get return type */
   if (return_type_obj) {
-    return_type = (gd_type_t)PyInt_AsLong(return_type_obj);
+    return_type = (gd_type_t)gdpy_long_from_pyobj(return_type_obj);
     if (PyErr_Occurred()) {
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
   } else {
     return_type = gd_native_type(self->D, field_code);
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
   }
 
+  /* Handle GD_NULL */
   if (return_type == GD_NULL) {
     if (len == 0)
       gd_get_carray(self->D, field_code, GD_NULL, NULL);
@@ -413,13 +499,16 @@ static PyObject *gdpy_dirfile_getcarray(struct gdpy_dirfile_t *self,
       gd_get_carray_slice(self->D, field_code, start, (size_t)len, GD_NULL,
           NULL);
 
-    PYGD_CHECK_ERROR(self->D, NULL);
+    PyMem_Free(field_code);
+
+    GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
     Py_INCREF(Py_None);
     dreturn("%p", Py_None);
     return Py_None;
   }
 
+  /* Non-GD_NULL return_type */
   if (len == 0) {
     len = gd_array_len(self->D, field_code);
     if (len > start)
@@ -440,16 +529,17 @@ static PyObject *gdpy_dirfile_getcarray(struct gdpy_dirfile_t *self,
       pyobj = PyArray_SimpleNew(1, dims, gdpy_npytype_from_type(return_type));
       data = PyArray_DATA(pyobj);
     } else
-      data = malloc(len * GD_SIZE(return_type));
+      data = malloc((size_t)len * GD_SIZE(return_type));
 
     gd_get_carray_slice(self->D, field_code, start, (size_t)len, return_type,
         data);
+    PyMem_Free(field_code);
 
     if (!as_list)
-      PYGD_CHECK_ERROR(self->D, NULL);
+      GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
     else {
-      PYGD_CHECK_ERROR2(self->D, NULL, free(data));
-      pyobj = gdpy_convert_to_pylist(data, return_type, len);
+      GDPY_CHECK_ERROR2(self->D, NULL, free(data), self->char_enc);
+      pyobj = gdpy_convert_to_pylist(data, return_type, (size_t)len);
 
       free(data);
     }
@@ -463,7 +553,7 @@ static PyObject *gdpy_dirfile_getconstant(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"field_code", "return_type", NULL};
-  const char *field_code;
+  char *field_code;
   PyObject *return_type_obj = NULL;
   gd_type_t return_type;
   char data[16];
@@ -472,8 +562,8 @@ static PyObject *gdpy_dirfile_getconstant(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|O:pygetdata.dirfile.get_constant", keywords, &field_code,
-        &return_type_obj))
+        "et|O:pygetdata.dirfile.get_constant", keywords, self->char_enc,
+        &field_code, &return_type_obj))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -481,21 +571,24 @@ static PyObject *gdpy_dirfile_getconstant(struct gdpy_dirfile_t *self,
 
   /* get return type */
   if (return_type_obj) {
-    return_type = (gd_type_t)PyInt_AsLong(return_type_obj);
+    return_type = (gd_type_t)gdpy_long_from_pyobj(return_type_obj);
     if (PyErr_Occurred()) {
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
   } else {
     return_type = gd_native_type(self->D, field_code);
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
   }
 
   gd_get_constant(self->D, field_code, return_type, data);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  PyMem_Free(field_code);
+
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_convert_to_pyobj(data, return_type);
+  pyobj = gdpy_convert_to_pyobj(data, return_type, 1);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -505,23 +598,25 @@ static PyObject *gdpy_dirfile_arraylen(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   size_t len;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.array_len",
-        keywords, &field_code)) {
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.array_len",
+        keywords, self->char_enc, &field_code))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   len = gd_array_len(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)len);
+  pyobj = gdpyint_fromlong((long)len);
   dreturn("%p", pyobj);
   return pyobj;
 }
@@ -533,8 +628,8 @@ static PyObject *gdpy_dirfile_carraylen(struct gdpy_dirfile_t *self,
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  PyErr_WarnEx(PyExc_DeprecationWarning, "pygetdata.dirfile.carray_len is "
-      "deprecated; use pygetdata.dirfile.array_len instead.", 1);
+  PyErr_Warn(PyExc_DeprecationWarning, "pygetdata.dirfile.carray_len is "
+      "deprecated; use pygetdata.dirfile.array_len instead.");
 
   pyobj = gdpy_dirfile_arraylen(self, args, keys);
 
@@ -563,15 +658,18 @@ static PyObject *gdpy_dirfile_carrays(struct gdpy_dirfile_t *self,
 
   fields = gd_field_list_by_type(self->D, GD_CARRAY_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   carrays = gd_carrays(self->D, (gd_type_t)return_type);
 
   pyobj = PyList_New(0);
 
   for (i = 0; carrays[i].n != 0; ++i) {
-    PyObject *pydata;
-    if (!as_list) {
+    PyObject *pydata, *name;
+    if (return_type == GD_NULL) {
+      Py_INCREF(Py_None);
+      pydata = Py_None;
+    } else if (!as_list) {
       dims[0] = (npy_intp)carrays[i].n;
       pydata = PyArray_SimpleNew(1, dims, gdpy_npytype_from_type(return_type));
       memcpy(PyArray_DATA(pydata), carrays[i].d, GD_SIZE(return_type) *
@@ -579,7 +677,16 @@ static PyObject *gdpy_dirfile_carrays(struct gdpy_dirfile_t *self,
     } else
       pydata = gdpy_convert_to_pylist(carrays[i].d, return_type, carrays[i].n);
 
-    gdpylist_append(pyobj, Py_BuildValue("sN", fields[i], pydata));
+    name = gdpyobj_from_string(fields[i], self->char_enc);
+
+    if (name == NULL) {
+      Py_DECREF(pydata);
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name, pydata));
   }
 
   dreturn("%p", pyobj);
@@ -607,18 +714,27 @@ static PyObject *gdpy_dirfile_getconstants(struct gdpy_dirfile_t *self,
 
   fields = gd_field_list_by_type(self->D, GD_CONST_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   values = gd_constants(self->D, (gd_type_t)return_type);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyList_New(0);
 
-  for (i = 0; fields[i] != NULL; ++i)
-    gdpylist_append(pyobj, Py_BuildValue("sN", fields[i],
+  for (i = 0; fields[i] != NULL; ++i) {
+    PyObject *name = gdpyobj_from_string(fields[i], self->char_enc);
+
+    if (name == NULL) {
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name, 
           gdpy_convert_to_pyobj(values + i * GD_SIZE(return_type),
-            return_type)));
+            return_type, 1)));
+  }
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -629,7 +745,7 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = { "field_code", "return_type", "first_frame",
     "first_sample", "num_frames", "num_samples", "as_list", NULL };
-  const char *field_code;
+  char *field_code;
   PY_LONG_LONG first_frame = 0, first_sample = 0;
   PyObject *num_frames_obj = NULL, *num_samples_obj = NULL;
   PyObject *return_type_obj = NULL;
@@ -644,49 +760,52 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|OLLOOi:pygetdata.dirfile.getdata", keywords, &field_code,
-        &return_type_obj, &first_frame, &first_sample, &num_frames_obj,
-        &num_samples_obj, &as_list))
+        "et|OLLOOi:pygetdata.dirfile.getdata", keywords, self->char_enc,
+        &field_code, &return_type_obj, &first_frame, &first_sample,
+        &num_frames_obj, &num_samples_obj, &as_list))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
-  PYGD_CHECK_ERROR(self->D, NULL);
-
   /* get return type */
   if (return_type_obj) {
-    return_type = (gd_type_t)PyInt_AsLong(return_type_obj);
+    return_type = (gd_type_t)gdpy_long_from_pyobj(return_type_obj);
     if (PyErr_Occurred()) {
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
   } else {
     return_type = gd_native_type(self->D, field_code);
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
   }
 
   if (num_frames_obj) {
-    num_frames = PyInt_AsLong(num_frames_obj);
+    num_frames = gdpy_long_from_pyobj(num_frames_obj);
     if (num_frames == -1 && PyErr_Occurred()) {
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     } else if (num_frames < 0) {
       PyErr_SetString(PyExc_ValueError, "pygetdata.dirfile.gd_getdata(): "
           "num_frames must be non-negative");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
   }
 
   if (num_samples_obj) {
-    num_samples = PyInt_AsLong(num_samples_obj);
+    num_samples = gdpy_long_from_pyobj(num_samples_obj);
     if (num_samples == -1 && PyErr_Occurred()) {
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     } else if (num_samples < 0) {
       PyErr_SetString(PyExc_ValueError, "pygetdata.dirfile.gd_getdata(): "
           "num_samples must be non-negative");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
@@ -700,11 +819,11 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
   if (read_to_end || num_frames) {
     spf = gd_spf(self->D, field_code);
 
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
 
     if (read_to_end) {
       num_samples = gd_nframes64(self->D) * spf;
-      PYGD_CHECK_ERROR(self->D, NULL);
+      GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
 
       /* don't read past the frame indicated by nframes */
       num_samples -= first_frame * spf - first_sample;
@@ -719,11 +838,13 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
   if (return_type == GD_NULL) {
     ns = gd_getdata64(self->D, field_code, first_frame, first_sample, 0,
         (size_t)num_samples, GD_NULL, NULL);
+    PyMem_Free(field_code);
     
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
     pyobj = PyLong_FromLongLong(ns);
   } else if (num_samples == 0) {
+    PyMem_Free(field_code);
     if (!as_list)
       pyobj = PyArray_ZEROS(1, dims, gdpy_npytype_from_type(return_type), 0);
     else
@@ -739,9 +860,10 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
 
     ns = gd_getdata64(self->D, field_code, first_frame, first_sample, 0,
         (size_t)num_samples, return_type, data);
+    PyMem_Free(field_code);
 
     if (!as_list) {
-      PYGD_CHECK_ERROR(self->D, NULL);
+      GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
       /* resize, if necessary */
       if (ns < num_samples) {
         PyObject *check;
@@ -759,7 +881,7 @@ static PyObject *gdpy_dirfile_getdata(struct gdpy_dirfile_t *self,
                              INCREF'd Py_None on success */
       }
     } else {
-      PYGD_CHECK_ERROR2(self->D, NULL, free(data));
+      GDPY_CHECK_ERROR2(self->D, NULL, free(data), self->char_enc);
       pyobj = gdpy_convert_to_pylist(data, return_type, ns);
 
       free(data);
@@ -774,15 +896,14 @@ static PyObject *gdpy_dirfile_getentry(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"field_code", NULL};
-  const char *field_code;
+  char *field_code;
   struct gdpy_entry_t *obj;
   gd_entry_t *E;
-  int e;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.entry",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.entry",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -791,19 +912,16 @@ static PyObject *gdpy_dirfile_getentry(struct gdpy_dirfile_t *self,
   E = malloc(sizeof(gd_entry_t));
 
   if (E == NULL) {
+    PyMem_Free(field_code);
     PyErr_NoMemory();
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_entry(self->D, field_code, E);
+  PyMem_Free(field_code);
 
-  if ((e = gd_error(self->D))) {
-    PYGD_REPORT_ERROR(self->D,e);
-    free(E);
-    dreturn("%p", NULL);
-    return NULL;
-  }
+  GDPY_CHECK_ERROR2(self->D, NULL, free(E), self->char_enc);
 
   obj = (struct gdpy_entry_t*)gdpy_entry.tp_alloc(&gdpy_entry, 0);
 
@@ -816,6 +934,11 @@ static PyObject *gdpy_dirfile_getentry(struct gdpy_dirfile_t *self,
   }
 
   obj->E = E;
+
+  /* These entry objects copy the dirfile's character_encoding, not the global
+   * pygetdata.character_encoding
+   */
+  obj->char_enc = self->char_enc;
   Py_INCREF(obj);
   dreturn("%p", obj);
   return (PyObject*)obj;
@@ -828,7 +951,7 @@ static PyObject *gdpy_dirfile_geterror(struct gdpy_dirfile_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  error = PyInt_FromLong(gd_error(self->D));
+  error = gdpyint_fromlong(gd_error(self->D));
 
   dreturn("%p", error);
   return error;
@@ -841,7 +964,7 @@ static PyObject *gdpy_dirfile_geterrorcount(struct gdpy_dirfile_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  count = PyInt_FromLong(gd_error_count(self->D));
+  count = gdpyint_fromlong(gd_error_count(self->D));
 
   dreturn("%p", count);
   return count;
@@ -883,24 +1006,26 @@ static PyObject *gdpy_dirfile_getfragmentindex(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"field_code", NULL};
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   int index;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.fragment_index", keywords, &field_code))
+        "et:pygetdata.dirfile.fragment_index", keywords, self->char_enc,
+        &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   index = gd_fragment_index(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(index);
+  pyobj = gdpyint_fromlong(index);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -915,7 +1040,7 @@ static PyObject *gdpy_dirfile_geterrorstring(struct gdpy_dirfile_t *self,
   dtrace("%p, %p", self, closure);
 
   estring = gd_error_string(self->D, NULL, 0);
-  pyobj = PyString_FromString(estring);
+  pyobj = gdpyobj_from_estring(estring, self->char_enc);
   free(estring);
 
   dreturn("%p", pyobj);
@@ -931,9 +1056,9 @@ static PyObject *gdpy_dirfile_getvectorlist(struct gdpy_dirfile_t *self)
 
   vectors = gd_vector_list(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(vectors);
+  pyobj = gdpyobj_from_strarr(vectors, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -961,9 +1086,9 @@ static PyObject *gdpy_dirfile_getfieldlist(struct gdpy_dirfile_t *self,
   else
     fields = gd_field_list_by_type(self->D, (gd_entype_t)type);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(fields);
+  pyobj = gdpyobj_from_strarr(fields, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -973,20 +1098,21 @@ static PyObject *gdpy_dirfile_flush(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code = NULL;
+  char *field_code = NULL;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "|s:pygetdata.dirfile.flush",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "|et:pygetdata.dirfile.flush",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_flush(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -997,20 +1123,21 @@ static PyObject *gdpy_dirfile_sync(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code = NULL;
+  char *field_code = NULL;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "|s:pygetdata.dirfile.sync",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "|et:pygetdata.dirfile.sync",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_sync(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1021,20 +1148,22 @@ static PyObject *gdpy_dirfile_raw_close(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code = NULL;
+  char *field_code = NULL;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "|s:pygetdata.dirfile.raw_close",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "|et:pygetdata.dirfile.raw_close", keywords, self->char_enc,
+        &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_raw_close(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1046,7 +1175,7 @@ static PyObject *gdpy_dirfile_include(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = { "file", "fragment_index", "flags", "prefix", "suffix",
     NULL };
-  const char *file = NULL;
+  char *file = NULL;
   int fragment_index = 0;
   unsigned long flags = 0;
   char *prefix = NULL, *suffix = NULL;
@@ -1056,8 +1185,9 @@ static PyObject *gdpy_dirfile_include(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|ikss:pygetdata.dirfile.include", keywords, &file, &fragment_index,
-        &flags, &prefix, &suffix))
+        "et|iketet:pygetdata.dirfile.include", keywords, self->char_enc, &file,
+        &fragment_index, &flags, self->char_enc, &prefix, self->char_enc,
+        &suffix))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1067,15 +1197,18 @@ static PyObject *gdpy_dirfile_include(struct gdpy_dirfile_t *self,
 
   index = gd_include_affix(self->D, file, fragment_index, prefix, suffix,
       flags);
+  PyMem_Free(file);
+  PyMem_Free(prefix);
+  PyMem_Free(suffix);
 
   if (self->callback_exception) {
     dreturn("%p", NULL);
     return NULL;
   }
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(index);
+  pyobj = gdpyint_fromlong(index);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1086,20 +1219,21 @@ static PyObject *gdpy_dirfile_madd(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = { "entry", "parent", NULL };
   struct gdpy_entry_t *entry = NULL;
-  const char *parent;
+  char *parent;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "O!s:pygetdata.dirfile.madd",
-        keywords, &gdpy_entry, &entry, &parent))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "O!et:pygetdata.dirfile.madd",
+        keywords, &gdpy_entry, &entry, self->char_enc, &parent))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_madd(self->D, entry->E, parent);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1110,21 +1244,24 @@ static PyObject *gdpy_dirfile_maddspec(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "spec", "parent", NULL };
-  const char *spec;
-  const char *parent;
+  char *spec;
+  char *parent;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "ss:pygetdata.dirfile.madd_spec",
-        keywords, &spec, &parent))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "etet:pygetdata.dirfile.madd_spec", keywords, self->char_enc, &spec,
+        self->char_enc, &parent))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_madd_spec(self->D, spec, parent);
+  PyMem_Free(parent);
+  PyMem_Free(spec);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1135,22 +1272,24 @@ static PyObject *gdpy_dirfile_malterspec(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "spec", "parent", "recode", NULL };
-  const char *spec, *parent;
+  char *spec, *parent;
   int recode = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "ss|i:pygetdata.dirfile.malter_spec", keywords, &spec, &parent,
-        &recode))
+        "etet|i:pygetdata.dirfile.malter_spec", keywords, self->char_enc, &spec,
+        self->char_enc, &parent, &recode))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_malter_spec(self->D, spec, parent, recode);
+  PyMem_Free(parent);
+  PyMem_Free(spec);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1162,7 +1301,7 @@ static PyObject *gdpy_dirfile_mcarrays(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = {"parent", "return_type", "as_list", NULL};
   const char **fields;
-  const char *parent;
+  char *parent;
   int as_list = 0, i, return_type;
   const gd_carray_t *carrays;
   PyObject *pyobj;
@@ -1171,8 +1310,8 @@ static PyObject *gdpy_dirfile_mcarrays(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "si|i:pygetdata.dirfile.mcarrays", keywords, &parent, &return_type,
-        &as_list))
+        "eti|i:pygetdata.dirfile.mcarrays", keywords, self->char_enc, &parent,
+        &return_type, &as_list))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1180,15 +1319,20 @@ static PyObject *gdpy_dirfile_mcarrays(struct gdpy_dirfile_t *self,
 
   fields = gd_mfield_list_by_type(self->D, parent, GD_CARRAY_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(parent), self->char_enc);
 
   carrays = gd_mcarrays(self->D, parent, (gd_type_t)return_type);
+  PyMem_Free(parent);
 
   pyobj = PyList_New(0);
 
   for (i = 0; carrays[i].n != 0; ++i) {
-    PyObject *pydata;
-    if (!as_list) {
+    PyObject *pydata, *name;
+
+    if (return_type == GD_NULL) {
+      Py_INCREF(Py_None);
+      pydata = Py_None;
+    } else if (!as_list) {
       dims[0] = (npy_intp)carrays[i].n;
       pydata = PyArray_SimpleNew(1, dims, gdpy_npytype_from_type(return_type));
       memcpy(PyArray_DATA(pydata), carrays[i].d, GD_SIZE(return_type) *
@@ -1196,7 +1340,16 @@ static PyObject *gdpy_dirfile_mcarrays(struct gdpy_dirfile_t *self,
     } else
       pydata = gdpy_convert_to_pylist(carrays[i].d, return_type, carrays[i].n);
 
-    gdpylist_append(pyobj, Py_BuildValue("sN", fields[i], pydata));
+    name = gdpyobj_from_string(fields[i], self->char_enc);
+
+    if (name == NULL) {
+      Py_DECREF(pydata);
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name, pydata));
   }
 
   dreturn("%p", pyobj);
@@ -1210,14 +1363,15 @@ static PyObject *gdpy_dirfile_getmconstants(struct gdpy_dirfile_t *self,
   char *keywords[] = {"parent", "return_type", NULL};
   const char **fields;
   const char *values;
-  const char *parent = NULL;
+  char *parent = NULL;
   int return_type;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "si:pygetdata.dirfile.mconstants", keywords, &parent, &return_type))
+        "eti:pygetdata.dirfile.mconstants", keywords, self->char_enc, &parent,
+        &return_type))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1225,18 +1379,28 @@ static PyObject *gdpy_dirfile_getmconstants(struct gdpy_dirfile_t *self,
 
   fields = gd_mfield_list_by_type(self->D, parent, GD_CONST_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(parent), self->char_enc);
 
   values = gd_mconstants(self->D, parent, (gd_type_t)return_type);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyList_New(0);
 
-  for (i = 0; fields[i] != NULL; ++i)
-    gdpylist_append(pyobj, Py_BuildValue("sN", fields[i],
+  for (i = 0; fields[i] != NULL; ++i) {
+    PyObject *name = gdpyobj_from_string(fields[i], self->char_enc);
+
+    if (name == NULL) {
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name,
           gdpy_convert_to_pyobj(values + i * GD_SIZE(return_type),
-            return_type)));
+            return_type, 1)));
+  }
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1248,7 +1412,7 @@ static PyObject *gdpy_dirfile_metaflush(struct gdpy_dirfile_t *self)
 
   gd_metaflush(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1260,14 +1424,15 @@ static PyObject *gdpy_dirfile_getmfieldlist(struct gdpy_dirfile_t *self,
 {
   const char **fields;
   char *keywords[] = { "parent", "type", NULL };
-  const char *parent = NULL;
+  char *parent = NULL;
   int type = GD_NO_ENTRY;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s|i:pygetdata.dirfile.field_list_by_type", keywords, &parent, &type))
+        "et|i:pygetdata.dirfile.field_list_by_type", keywords, self->char_enc,
+        &parent, &type))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1277,10 +1442,11 @@ static PyObject *gdpy_dirfile_getmfieldlist(struct gdpy_dirfile_t *self,
     fields = gd_mfield_list(self->D, parent);
   else
     fields = gd_mfield_list_by_type(self->D, parent, (gd_entype_t)type);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(fields);
+  pyobj = gdpyobj_from_strarr(fields, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1296,9 +1462,9 @@ static PyObject *gdpy_dirfile_getname(struct gdpy_dirfile_t *self,
 
   name = gd_dirfilename(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyString_FromString(name);
+  pyobj = gdpyobj_from_path(name);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1311,13 +1477,13 @@ static PyObject *gdpy_dirfile_getmstrings(struct gdpy_dirfile_t *self,
   char *keywords[] = {"parent", NULL};
   const char **fields;
   const char **values;
-  const char *parent = NULL;
+  char *parent = NULL;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.mstrings",
-        keywords, &parent))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.mstrings",
+        keywords, self->char_enc, &parent))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1325,16 +1491,33 @@ static PyObject *gdpy_dirfile_getmstrings(struct gdpy_dirfile_t *self,
 
   fields = gd_mfield_list_by_type(self->D, parent, GD_STRING_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(parent), self->char_enc);
 
   values = gd_mstrings(self->D, parent);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyList_New(0);
 
-  for (i = 0; fields[i] != NULL; ++i)
-    gdpylist_append(pyobj, Py_BuildValue("ss", fields[i], values[i]));
+  for (i = 0; fields[i] != NULL; ++i) {
+    PyObject *name = NULL, *value = NULL;
+
+    name = gdpyobj_from_string(fields[i], self->char_enc);
+    
+    if (name)
+      value = gdpyobj_from_string(values[i], self->char_enc);
+
+    if (value == NULL) {
+      if (name)
+        Py_DECREF(name);
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name, value));
+  }
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1344,24 +1527,25 @@ static PyObject *gdpy_dirfile_getmvectorlist(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"parent", NULL};
-  const char *parent = NULL;
+  char *parent = NULL;
   const char **fields;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.mvector_list", keywords, &parent))
+        "et:pygetdata.dirfile.mvector_list", keywords, self->char_enc, &parent))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   fields = gd_mvector_list(self->D, parent);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(fields);
+  pyobj = gdpyobj_from_strarr(fields, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1371,24 +1555,26 @@ static PyObject *gdpy_dirfile_getrawfilename(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   char *filename;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.raw_filename", keywords, &field_code))
+        "et:pygetdata.dirfile.raw_filename", keywords, self->char_enc,
+        &field_code))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   filename = gd_raw_filename(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyString_FromString(filename);
+  pyobj = gdpyobj_from_path(filename);
   free(filename);
   dreturn("%p", pyobj);
   return pyobj;
@@ -1398,24 +1584,26 @@ static PyObject *gdpy_dirfile_getnativetype(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   gd_type_t ntype;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.native_type", keywords, &field_code))
+        "et:pygetdata.dirfile.native_type", keywords, self->char_enc,
+        &field_code))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   ntype = gd_native_type(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)ntype);
+  pyobj = gdpyint_fromlong((long)ntype);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1425,7 +1613,7 @@ static PyObject *gdpy_dirfile_getnativetypename(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   char tbuffer[11];
   PyObject *pyobj;
   gd_type_t t;
@@ -1433,21 +1621,23 @@ static PyObject *gdpy_dirfile_getnativetypename(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.native_type_name", keywords, &field_code))
+        "et:pygetdata.dirfile.native_type_name", keywords, self->char_enc,
+        &field_code))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   t = gd_native_type(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   sprintf(tbuffer, "%s%i", ((t & GD_COMPLEX) ? "COMPLEX" :
         (t & GD_IEEE754) ? "FLOAT" : (t & GD_SIGNED) ?  "INT" : "UINT"),
       (int)(8 * GD_SIZE(t)));
 
-  pyobj = PyString_FromString(tbuffer);
+  pyobj = gdpystrobj_from_string(tbuffer);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1475,9 +1665,9 @@ static PyObject *gdpy_dirfile_getnfields(struct gdpy_dirfile_t *self,
   else
     nfields = gd_nfields_by_type(self->D, (gd_entype_t)type);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)nfields);
+  pyobj = gdpyint_fromlong((long)nfields);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1493,9 +1683,9 @@ static PyObject *gdpy_dirfile_getnfragments(struct gdpy_dirfile_t *self,
 
   nfragments = gd_nfragments(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(nfragments);
+  pyobj = gdpyint_fromlong(nfragments);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1511,7 +1701,7 @@ static PyObject *gdpy_dirfile_getnframes(struct gdpy_dirfile_t *self,
 
   nframes = gd_nframes64(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromLongLong(nframes);
 
@@ -1523,15 +1713,16 @@ static PyObject *gdpy_dirfile_getnmfields(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "parent", "type", NULL };
-  const char *parent = NULL;
+  char *parent = NULL;
   int type = GD_NO_ENTRY;
   unsigned int nmfields;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s|i:pygetdata.dirfile.nmfields",
-        keywords, &parent, &type))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "et|i:pygetdata.dirfile.nmfields", keywords, self->char_enc, &parent,
+        &type))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1541,10 +1732,11 @@ static PyObject *gdpy_dirfile_getnmfields(struct gdpy_dirfile_t *self,
     nmfields = gd_nmfields(self->D, parent);
   else
     nmfields = gd_nmfields_by_type(self->D, parent, (gd_entype_t)type);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)nmfields);
+  pyobj = gdpyint_fromlong((long)nmfields);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1554,24 +1746,25 @@ static PyObject *gdpy_dirfile_getnmvectors(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "parent", NULL };
-  const char *parent = NULL;
+  char *parent = NULL;
   PyObject *pyobj;
   unsigned int nmvectors;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.nmvectors", keywords, &parent))
+        "et:pygetdata.dirfile.nmvectors", keywords, self->char_enc, &parent))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   nmvectors = gd_nmvectors(self->D, parent);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)nmvectors);
+  pyobj = gdpyint_fromlong((long)nmvectors);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1581,22 +1774,23 @@ static PyObject *gdpy_dirfile_getbof(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   gd_off64_t bof;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.bof", keywords, &field_code))
+        "et:pygetdata.dirfile.bof", keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   bof = gd_bof64(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromLongLong(bof);
 
@@ -1608,22 +1802,23 @@ static PyObject *gdpy_dirfile_geteof(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   gd_off64_t eof;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.eof", keywords, &field_code))
+        "et:pygetdata.dirfile.eof", keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   eof = gd_eof64(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromLongLong(eof);
 
@@ -1640,9 +1835,9 @@ static PyObject *gdpy_dirfile_getnvectors(struct gdpy_dirfile_t *self)
 
   nvectors = gd_nvectors(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)nvectors);
+  pyobj = gdpyint_fromlong((long)nvectors);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1658,7 +1853,7 @@ static PyObject *gdpy_dirfile_getreference(struct gdpy_dirfile_t *self,
 
   ref = gd_reference(self->D, NULL);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   /* Empty dirfile */
   if (ref == NULL) {
@@ -1667,7 +1862,7 @@ static PyObject *gdpy_dirfile_getreference(struct gdpy_dirfile_t *self,
     return Py_None;
   }
 
-  pyobj = PyString_FromString(ref);
+  pyobj = gdpyobj_from_string(ref, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1676,11 +1871,15 @@ static PyObject *gdpy_dirfile_getreference(struct gdpy_dirfile_t *self,
 static int gdpy_dirfile_setreference(struct gdpy_dirfile_t *self,
     PyObject *value, void *closure)
 {
-  const char *ref;
+  char *ref = NULL;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  ref = PyString_AsString(value);
+  if (value == NULL)
+    PyErr_SetString(PyExc_TypeError, "deletion of reference is not supported");
+  else
+    ref = gdpy_string_from_pyobj(value, self->char_enc,
+        "reference field must be string");
 
   /* TypeError already raised on error */
   if (ref == NULL) {
@@ -1689,8 +1888,9 @@ static int gdpy_dirfile_setreference(struct gdpy_dirfile_t *self,
   }
 
   gd_reference(self->D, ref);
+  free(ref);
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -1700,15 +1900,16 @@ static PyObject *gdpy_dirfile_getstring(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   size_t len;
   char *data;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.get_string",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "et:pygetdata.dirfile.get_string", keywords, self->char_enc,
+        &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1716,20 +1917,22 @@ static PyObject *gdpy_dirfile_getstring(struct gdpy_dirfile_t *self,
 
   len = gd_get_string(self->D, field_code, 0, NULL);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR2(self->D, NULL, PyMem_Free(field_code), self->char_enc);
 
   data = malloc(len);
   if (data == NULL) {
+    PyMem_Free(field_code);
     PyErr_NoMemory();
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_get_string(self->D, field_code, len, data);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR2(self->D, NULL, free(data));
+  GDPY_CHECK_ERROR2(self->D, NULL, free(data), self->char_enc);
 
-  pyobj = PyString_FromString(data);
+  pyobj = gdpyobj_from_string(data, self->char_enc);
 
   free(data);
 
@@ -1748,16 +1951,32 @@ static PyObject *gdpy_dirfile_getstrings(struct gdpy_dirfile_t *self)
 
   fields = gd_field_list_by_type(self->D, GD_STRING_ENTRY);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   values = gd_strings(self->D);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyList_New(0);
 
-  for (i = 0; fields[i] != NULL; ++i)
-    gdpylist_append(pyobj, Py_BuildValue("ss", fields[i], values[i]));
+  for (i = 0; fields[i] != NULL; ++i) {
+    PyObject *name = NULL, *value = NULL;
+
+    name = gdpyobj_from_string(fields[i], self->char_enc);
+    
+    if (name)
+      value = gdpyobj_from_string(values[i], self->char_enc);
+
+    if (value == NULL) {
+      if (name)
+        Py_DECREF(name);
+      Py_DECREF(pyobj);
+      dreturn("%p", NULL);
+      return NULL;
+    }
+
+    gdpylist_append(pyobj, Py_BuildValue("NN", name, value));
+  }
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -1767,7 +1986,7 @@ static PyObject *gdpy_dirfile_putconstant(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = {"field_code", "value", "type", NULL};
-  const char *field_code;
+  char *field_code;
   PyObject *value;
   int type = GD_UNKNOWN;
   union gdpy_quadruple_value data;
@@ -1776,8 +1995,8 @@ static PyObject *gdpy_dirfile_putconstant(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "sO|i:pygetdata.dirfile.put_constant", keywords, &field_code, &value,
-        &type))
+        "etO|i:pygetdata.dirfile.put_constant", keywords, self->char_enc,
+        &field_code, &value, &type))
   {
     dreturn("%p", NULL);
     return NULL;
@@ -1786,6 +2005,7 @@ static PyObject *gdpy_dirfile_putconstant(struct gdpy_dirfile_t *self,
   data_type = gdpy_convert_from_pyobj(value, &data, type);
 
   if (data_type == -1) {
+    PyMem_Free(field_code);
     dreturn("%p", NULL);
     return NULL;
   }
@@ -1799,7 +2019,9 @@ static PyObject *gdpy_dirfile_putconstant(struct gdpy_dirfile_t *self,
   else
     gd_put_constant(self->D, field_code, GD_UINT64, &data.u);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  PyMem_Free(field_code);
+
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -1810,7 +2032,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", "data", "type", "start", NULL };
-  const char *field_code;
+  char *field_code;
   unsigned int start = 0;
   size_t len;
   int type = GD_UNKNOWN;
@@ -1820,8 +2042,9 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "sO|iI:pygetdata.dirfile.put_carray", keywords, &field_code, &pyobj,
-        &type, &start)) {
+        "etO|iI:pygetdata.dirfile.put_carray", keywords, self->char_enc,
+        &field_code, &pyobj, &type, &start))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
@@ -1831,6 +2054,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
     if (PyArray_NDIM(pyobj) != 1) {
       PyErr_SetString(PyExc_ValueError,
           "pygetdata.dirfile.put_carray() argument 2 must be one dimensional");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
@@ -1841,6 +2065,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
       PyErr_SetString(PyExc_TypeError,
           "pygetdata.dirfile.put_carray() argument 2 must be list or NumPy "
           "array.");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
@@ -1857,6 +2082,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
       if (type == GD_UNKNOWN) {
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.put_carray() unknown data type for argument 2.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1864,6 +2090,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
       if (!(PyArray_FLAGS(pyobj) & NPY_ALIGNED)) {
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.put_carray() argument 2 must be aligned.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1871,6 +2098,7 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
       if (!(PyArray_FLAGS(pyobj) & NPY_C_CONTIGUOUS)) {
         PyErr_SetString(PyExc_ValueError, "pygetdata.dirfile.put_carray()"
             " argument 2 must be C-style contiguous.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1884,17 +2112,19 @@ static PyObject *gdpy_dirfile_putcarray(struct gdpy_dirfile_t *self,
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.put_carray() unknown data type for argument 2.");
         free(data);
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
     }
 
     gd_put_carray_slice(self->D, field_code, start, len, type, data);
+    PyMem_Free(field_code);
 
     if (have_ndarray)
-      PYGD_CHECK_ERROR(self->D, NULL);
+      GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
     else {
-      PYGD_CHECK_ERROR2(self->D, NULL, free(data));
+      GDPY_CHECK_ERROR2(self->D, NULL, free(data), self->char_enc);
 
       free(data);
     }
@@ -1910,7 +2140,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
 {
   char *keywords[] = { "field_code", "data", "type", "first_frame",
     "first_sample", NULL };
-  const char *field_code;
+  char *field_code;
   PY_LONG_LONG first_frame = 0, first_sample = 0;
   int type = GD_UNKNOWN;
   PyObject *pyobj;
@@ -1920,8 +2150,9 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "sO|iLL:pygetdata.dirfile.putdata", keywords, &field_code, &pyobj,
-        &type, &first_frame, &first_sample)) {
+        "etO|iLL:pygetdata.dirfile.putdata", keywords, self->char_enc,
+        &field_code, &pyobj, &type, &first_frame, &first_sample))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
@@ -1931,6 +2162,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
     if (PyArray_NDIM(pyobj) != 1) {
       PyErr_SetString(PyExc_ValueError,
           "pygetdata.dirfile.putdata() argument 2 must be one dimensional");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
@@ -1941,6 +2173,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
       PyErr_SetString(PyExc_TypeError,
           "pygetdata.dirfile.putdata() argument 2 must be list or NumPy "
           "array.");
+      PyMem_Free(field_code);
       dreturn("%p", NULL);
       return NULL;
     }
@@ -1957,6 +2190,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
       if (type == GD_UNKNOWN) {
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.putdata() unknown data type for argument 2.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1964,6 +2198,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
       if (!(PyArray_FLAGS(pyobj) & NPY_ALIGNED)) {
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.putdata() argument 2 must be aligned.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1971,6 +2206,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
       if (!(PyArray_FLAGS(pyobj) & NPY_C_CONTIGUOUS)) {
         PyErr_SetString(PyExc_ValueError, "pygetdata.dirfile.putdata()"
             " argument 2 must be C-style contiguous.");
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1984,6 +2220,7 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
         PyErr_SetString(PyExc_ValueError,
             "pygetdata.dirfile.putdata() unknown data type for argument 2.");
         free(data);
+        PyMem_Free(field_code);
         dreturn ("%p", NULL);
         return NULL;
       }
@@ -1991,11 +2228,12 @@ static PyObject *gdpy_dirfile_putdata(struct gdpy_dirfile_t *self,
 
     ns = gd_putdata64(self->D, field_code, first_frame, first_sample, 0, ns,
         type, data);
+    PyMem_Free(field_code);
 
     if (!have_ndarray)
       free(data);
 
-    PYGD_CHECK_ERROR(self->D, NULL);
+    GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
   }
 
   pyobj = PyLong_FromLongLong(ns);
@@ -2008,21 +2246,24 @@ static PyObject *gdpy_dirfile_putstring(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", "data", NULL };
-  const char *field_code;
-  const char *data;
+  char *field_code;
+  char *data;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "ss:pygetdata.dirfile.put_string", keywords, &field_code, &data))
+        "etet:pygetdata.dirfile.put_string", keywords, self->char_enc,
+        &field_code, self->char_enc, &data))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   gd_put_string(self->D, field_code, data);
+  PyMem_Free(field_code);
+  PyMem_Free(data);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2033,23 +2274,25 @@ static PyObject *gdpy_dirfile_getspf(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   unsigned int spf;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.spf",
-        keywords, &field_code)) {
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.spf",
+        keywords, self->char_enc, &field_code))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   spf = gd_spf(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)spf);
+  pyobj = gdpyint_fromlong((long)spf);
   dreturn("%p", pyobj);
   return pyobj;
 }
@@ -2058,19 +2301,21 @@ static PyObject *gdpy_dirfile_validate(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.validate",
-        keywords, &field_code)) {
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.validate",
+        keywords, self->char_enc, &field_code))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   gd_validate(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2081,7 +2326,7 @@ static PyObject *gdpy_dirfile_getframenum(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", "value", "start", "end", NULL };
-  const char *field_code;
+  char *field_code;
   double value, frame;
   PY_LONG_LONG frame_start = 0;
   PY_LONG_LONG frame_end = 0;
@@ -2090,17 +2335,18 @@ static PyObject *gdpy_dirfile_getframenum(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "sd|LL:pygetdata.dirfile.framenum", keywords, &field_code, &value,
-        &frame_start, &frame_end))
+        "etd|LL:pygetdata.dirfile.framenum", keywords, self->char_enc,
+        &field_code, &value, &frame_start, &frame_end))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
- frame = gd_framenum_subset64(self->D, field_code, value, frame_start,
-     frame_end);
+  frame = gd_framenum_subset64(self->D, field_code, value, frame_start,
+      frame_end);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyFloat_FromDouble(frame);
   dreturn("%p", pyobj);
@@ -2140,7 +2386,7 @@ static PyObject *gdpy_dirfile_callback(struct gdpy_dirfile_t *self,
   gd_parser_callback(self->D, (pycallback == NULL) ? NULL :
       gdpy_callback_func, self);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2165,7 +2411,7 @@ static PyObject *gdpy_dirfile_uninclude(struct gdpy_dirfile_t *self,
 
   gd_uninclude(self->D, fragment_index, del);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2176,21 +2422,22 @@ static PyObject *gdpy_dirfile_move(struct gdpy_dirfile_t *self, PyObject *args,
     PyObject *keys)
 {
   char *keywords[] = { "field_code", "new_fragment", "flags", NULL };
-  const char *field_code;
+  char *field_code;
   int new_fragment;
   unsigned flags = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "si|I:pygetdata.dirfile.move",
-        keywords, &field_code, &new_fragment, &flags)) {
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "eti|I:pygetdata.dirfile.move",
+        keywords, self->char_enc, &field_code, &new_fragment, &flags)) {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   gd_move(self->D, field_code, new_fragment, flags);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2201,21 +2448,25 @@ static PyObject *gdpy_dirfile_rename(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "old_code", "new_name", "flags", NULL };
-  const char *old_code;
-  const char *new_name;
+  char *old_code;
+  char *new_name;
   unsigned flags = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "ss|I:pygetdata.dirfile.rename",
-        keywords, &old_code, &new_name, &flags)) {
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "etet|I:pygetdata.dirfile.rename", keywords, self->char_enc, &old_code,
+        self->char_enc, &new_name, &flags))
+  {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   gd_rename(self->D, old_code, new_name, flags);
+  PyMem_Free(old_code);
+  PyMem_Free(new_name);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2232,9 +2483,9 @@ static PyObject *gdpy_dirfile_getstandards(struct gdpy_dirfile_t *self,
 
   vers = gd_dirfile_standards(self->D, GD_VERSION_CURRENT);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(vers);
+  pyobj = gdpyint_fromlong(vers);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2243,11 +2494,14 @@ static PyObject *gdpy_dirfile_getstandards(struct gdpy_dirfile_t *self,
 static int gdpy_dirfile_setstandards(struct gdpy_dirfile_t *self,
     PyObject *value, void *closure)
 {
-  int vers;
+  int vers = 0;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  vers = (int)PyInt_AsLong(value);
+  if (value == NULL)
+    PyErr_SetString(PyExc_TypeError, "deletion of standards is not supported");
+  else
+    vers = (int)gdpy_long_from_pyobj(value);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -2256,7 +2510,7 @@ static int gdpy_dirfile_setstandards(struct gdpy_dirfile_t *self,
 
   gd_dirfile_standards(self->D, vers);
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -2266,7 +2520,7 @@ static PyObject *gdpy_dirfile_seek(struct gdpy_dirfile_t *self, PyObject *args,
     PyObject *keys)
 {
   char *keywords[] = { "field_code", "flags", "frame_num", "sample_num", NULL };
-  const char *field_code;
+  char *field_code;
   PY_LONG_LONG frame_num = 0, sample_num = 0;
   int flags;
   gd_off64_t pos;
@@ -2274,16 +2528,17 @@ static PyObject *gdpy_dirfile_seek(struct gdpy_dirfile_t *self, PyObject *args,
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "si|LL:pygetdata.dirfile.seek",
-        keywords, &field_code, &flags, &frame_num, &sample_num))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "eti|LL:pygetdata.dirfile.seek",
+        keywords, self->char_enc, &field_code, &flags, &frame_num, &sample_num))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   pos = gd_seek64(self->D, field_code, frame_num, sample_num, flags);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromLongLong((PY_LONG_LONG)pos);
 
@@ -2295,22 +2550,23 @@ static PyObject *gdpy_dirfile_tell(struct gdpy_dirfile_t *self, PyObject *args,
     PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   gd_off64_t pos;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "s:pygetdata.dirfile.tell",
-        keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.tell",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   pos = gd_tell64(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromLongLong((PY_LONG_LONG)pos);
 
@@ -2322,20 +2578,21 @@ static PyObject *gdpy_dirfile_hide(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.hide", keywords, &field_code))
+        "et:pygetdata.dirfile.hide", keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_hide(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2346,20 +2603,21 @@ static PyObject *gdpy_dirfile_unhide(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.unhide", keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.unhide",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_unhide(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2370,24 +2628,25 @@ static PyObject *gdpy_dirfile_naliases(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   long naliases;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.naliases", keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.naliases",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   naliases = gd_naliases(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(naliases);
+  pyobj = gdpyint_fromlong(naliases);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2397,23 +2656,26 @@ static PyObject *gdpy_dirfile_aliastarget(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code, *target;
+  char *field_code;
+  const char *target;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.alias_target", keywords, &field_code))
+        "et:pygetdata.dirfile.alias_target", keywords, self->char_enc,
+        &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   target = gd_alias_target(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyString_FromString(target);
+  pyobj = gdpyobj_from_string(target, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2423,24 +2685,25 @@ static PyObject *gdpy_dirfile_hidden(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
   long hidden;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.hidden", keywords, &field_code))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "et:pygetdata.dirfile.hidden",
+        keywords, self->char_enc, &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   hidden = gd_hidden(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong(hidden);
+  pyobj = gdpyint_fromlong(hidden);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2451,23 +2714,25 @@ static PyObject *gdpy_dirfile_aliaslist(struct gdpy_dirfile_t *self,
 {
   const char **fields;
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.alias_list", keywords, &field_code))
+        "et:pygetdata.dirfile.alias_list", keywords, self->char_enc,
+        &field_code))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   fields = gd_aliases(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(fields);
+  pyobj = gdpyobj_from_strarr(fields, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2477,22 +2742,24 @@ static PyObject *gdpy_dirfile_addalias(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = { "field_code", "target", "fragment_index", NULL };
-  const char *field_code, *target;
+  char *field_code, *target;
   int fragment_index = 0;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "ss|i:pygetdata.dirfile.add_alias", keywords, &field_code, &target,
-        &fragment_index))
+        "etet|i:pygetdata.dirfile.add_alias", keywords, self->char_enc,
+        &field_code, self->char_enc, &target, &fragment_index))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_add_alias(self->D, field_code, target, fragment_index);
+  PyMem_Free(field_code);
+  PyMem_Free(target);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2503,21 +2770,24 @@ static PyObject *gdpy_dirfile_maddalias(struct gdpy_dirfile_t *self,
     void *args, void *keys)
 {
   char *keywords[] = { "parent", "field_code", "target", NULL };
-  const char *field_code, *target, *parent;
+  char *field_code, *target, *parent;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "sss:pygetdata.dirfile.madd_alias", keywords, &parent, &field_code,
-        &target))
+        "etetet:pygetdata.dirfile.madd_alias", keywords, self->char_enc,
+        &parent, self->char_enc, &field_code, self->char_enc, &target))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   gd_madd_alias(self->D, parent, field_code, target);
+  PyMem_Free(field_code);
+  PyMem_Free(target);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -2529,21 +2799,22 @@ static PyObject *gdpy_dirfile_strtok(struct gdpy_dirfile_t *self,
 {
   char *token;
   char *keywords[] = { "string", NULL };
-  const char *string = NULL;
+  char *string = NULL;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "|s:pygetdata.dirfile.strtok",
-        keywords, &string))
+  if (!PyArg_ParseTupleAndKeywords(args, keys, "|et:pygetdata.dirfile.strtok",
+        keywords, self->char_enc, &string))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   token = gd_strtok(self->D, string);
+  PyMem_Free(string); /* gd_strtok make a copy of the string */
 
-  pyobj = PyString_FromString(token);
+  pyobj = gdpyobj_from_string(token, self->char_enc);
   free(token);
 
   dreturn("%p", pyobj);
@@ -2569,7 +2840,7 @@ static PyObject *gdpy_dirfile_desync(struct gdpy_dirfile_t *self,
 
   ret = gd_desync(self->D, flags);
 
-  pyobj = PyInt_FromLong((long)ret);
+  pyobj = gdpyint_fromlong((long)ret);
   dreturn("%p", pyobj);
   return pyobj;
 }
@@ -2584,7 +2855,7 @@ static PyObject *gdpy_dirfile_getflags(struct gdpy_dirfile_t *self,
 
   flags = gd_flags(self->D, 0, 0);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
   pyobj = PyLong_FromUnsignedLong(flags);
   dreturn("%p", pyobj);
@@ -2594,11 +2865,12 @@ static PyObject *gdpy_dirfile_getflags(struct gdpy_dirfile_t *self,
 static int gdpy_dirfile_setflags(struct gdpy_dirfile_t *self,
     PyObject *value, void *closure)
 {
-  unsigned long new_flags;
+  unsigned long new_flags = 0;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  new_flags = PyLong_AsUnsignedLong(value);
+  if (value)
+    new_flags = gdpy_ulong_from_pyobj(value);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -2607,7 +2879,7 @@ static int gdpy_dirfile_setflags(struct gdpy_dirfile_t *self,
 
   gd_flags(self->D, new_flags, ~new_flags);
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -2626,7 +2898,7 @@ static PyObject *gdpy_dirfile_getverboseprefix(struct gdpy_dirfile_t *self,
     return Py_None;
   }
 
-  pyobj = PyString_FromString(self->verbose_prefix);
+  pyobj = gdpystrobj_from_string(self->verbose_prefix);
   dreturn("%p", pyobj);
   return pyobj;
 }
@@ -2637,20 +2909,15 @@ static int gdpy_dirfile_setverboseprefix(struct gdpy_dirfile_t *self,
   dtrace("%p, %p, %p", self, value, closure);
 
   free(self->verbose_prefix);
-  if (value == Py_None)
+  if (value == NULL || value == Py_None)
     self->verbose_prefix = NULL;
-  else {
-    char *string = PyString_AsString(value);
-    if (string == NULL) {
-      dreturn("%i", -1);
-      return -1;
-    }
-    self->verbose_prefix = strdup(string);
-  }
+  else
+    self->verbose_prefix = gdpy_string_from_pyobj(value, self->char_enc,
+        "prefix must be string");
 
   gd_verbose_prefix(self->D, self->verbose_prefix);
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -2663,7 +2930,7 @@ static PyObject *gdpy_dirfile_getmplexlookback(struct gdpy_dirfile_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyInt_FromLong(self->mplex_lookback);
+  pyobj = gdpyint_fromlong(self->mplex_lookback);
   dreturn("%p", pyobj);
   return pyobj;
 }
@@ -2671,11 +2938,14 @@ static PyObject *gdpy_dirfile_getmplexlookback(struct gdpy_dirfile_t *self,
 static int gdpy_dirfile_setmplexlookback(struct gdpy_dirfile_t *self,
     PyObject *value, void *closure)
 {
-  int lookback;
+  int lookback = 0;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  lookback = (int)PyInt_AsLong(value);
+  if (value == NULL)
+    PyErr_SetString(PyExc_TypeError, "deletion of lookback is not supported");
+  else
+    lookback = (int)gdpy_long_from_pyobj(value);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -2686,7 +2956,7 @@ static int gdpy_dirfile_setmplexlookback(struct gdpy_dirfile_t *self,
 
   gd_mplex_lookback(self->D, lookback);
 
-  PYGD_CHECK_ERROR(self->D, -1);
+  GDPY_CHECK_ERROR(self->D, -1, self->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -2698,23 +2968,25 @@ static PyObject *gdpy_dirfile_nentries(struct gdpy_dirfile_t *self,
   char *keywords[] = { "parent", "type", "flags", NULL };
   unsigned int nentries, flags = 0;
   int type = 0;
-  const char *parent = NULL;
+  char *parent = NULL;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "|siI:pygetdata.dirfile.nentries", keywords, &parent, &type, &flags))
+        "|etiI:pygetdata.dirfile.nentries", keywords, self->char_enc, &parent,
+        &type, &flags))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   nentries = gd_nentries(self->D, parent, type, flags);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyInt_FromLong((long)nentries);
+  pyobj = gdpyint_fromlong((long)nentries);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2727,23 +2999,25 @@ static PyObject *gdpy_dirfile_entrylist(struct gdpy_dirfile_t *self,
   char *keywords[] = { "parent", "type", "flags", NULL };
   int type = 0;
   unsigned int flags = 0;
-  const char *parent = NULL;
+  char *parent = NULL;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "|siI:pygetdata.dirfile.entry_list", keywords, &parent, &type, &flags))
+        "|etiI:pygetdata.dirfile.entry_list", keywords, self->char_enc, &parent,
+        &type, &flags))
   {
     dreturn("%p", NULL);
     return NULL;
   }
 
   entries = gd_entry_list(self->D, parent, type, flags);
+  PyMem_Free(parent);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = gdpy_to_pystringlist(entries);
+  pyobj = gdpyobj_from_strarr(entries, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -2753,30 +3027,68 @@ static PyObject *gdpy_dirfile_linterptablename(struct gdpy_dirfile_t *self,
     PyObject *args, PyObject *keys)
 {
   char *keywords[] = { "field_code", NULL };
-  const char *field_code;
+  char *field_code;
   char *filename;
   PyObject *pyobj;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
-        "s:pygetdata.dirfile.linterp_tablename", keywords, &field_code))
+        "et:pygetdata.dirfile.linterp_tablename", keywords, self->char_enc,
+        &field_code))
   {
     dreturn ("%p", NULL);
     return NULL;
   }
 
   filename = gd_linterp_tablename(self->D, field_code);
+  PyMem_Free(field_code);
 
-  PYGD_CHECK_ERROR(self->D, NULL);
+  GDPY_CHECK_ERROR(self->D, NULL, self->char_enc);
 
-  pyobj = PyString_FromString(filename);
+  pyobj = gdpyobj_from_path(filename);
   free(filename);
   dreturn("%p", pyobj);
   return pyobj;
 }
 
+static PyObject *gdpy_dirfile_getcharencoding(struct gdpy_dirfile_t *self,
+    void *closure)
+{
+  dtrace("%p, %p", self, closure);
+
+  PyObject *pyobj = gdpy_charenc_obj(self->char_enc);
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+static int gdpy_dirfile_setcharencoding(struct gdpy_dirfile_t *self,
+    PyObject *value, void *closure)
+{
+  dtrace("%p, %p, %p", self, value, closure);
+
+  if (gdpy_parse_charenc(&self->char_enc, value)) {
+    dreturn("%i", -1);
+    return -1;
+  }
+  
+  dreturn("%i", 0);
+  return 0;
+}
+
 static PyGetSetDef gdpy_dirfile_getset[] = {
+  { "character_encoding", (getter)gdpy_dirfile_getcharencoding,
+    (setter)gdpy_dirfile_setcharencoding,
+    "The character encoding to use when representing Dirfile string data\n"
+      "and metadata in Python.  The initial value of this attribute is\n"
+      "copied from the value of the global pygetdata.character_encoding\n"
+      "at the time that the dirfile object is created, if the global value\n"
+      "is valid.  If the global pygetdata.character_encoding is invalid,\n"
+      "the initial value of this attribute is simply None.  Subsequent\n"
+      "changes affect only this object.  See the CHARACTER STRINGS section\n"
+      "in the pygetdata module documentation for further details.",
+    NULL },
   { "error", (getter)gdpy_dirfile_geterror, NULL,
     "The numerical error code encountered by the last call to the GetData\n"
       "library for this dirfile.  If the last call was successful, this\n"
@@ -2808,9 +3120,10 @@ static PyGetSetDef gdpy_dirfile_getset[] = {
     "The number of frames in the dirfile.  See gd_nframes(3).", NULL },
   { "reference", (getter)gdpy_dirfile_getreference,
     (setter)gdpy_dirfile_setreference,
-    "The reference field for the dirfile, which may be set to any existing\n"
-      "RAW field.  If no RAW fields are defined in the dirfile, this will\n"
-      "be None.  See gd_reference(3).",
+    "The reference field for the dirfile, which may be set to any\n"
+      "existing RAW field.  If no RAW fields are defined in the dirfile,\n"
+      /*--- handy ruler: closing quote as indicated (or earlier)---------\n" */
+      "this will be None.  See gd_reference(3).",
     NULL },
   { "standards", (getter)gdpy_dirfile_getstandards,
     (setter)gdpy_dirfile_setstandards,
@@ -2931,7 +3244,6 @@ static PyMethodDef gdpy_dirfile_methods[] = {
       "If omitted, the return type defaults to the native type of the field\n"
       "(see dirfile.native_type()).  If 'return_type' is pygetdata.NULL,\n"
       "None is returned on success.  See gd_get_constant(3)."
-      /* ------- handy ruler ---------------------------------------------| */
   },
   {"constants", (PyCFunction)gdpy_dirfile_getconstants,
     METH_VARARGS | METH_KEYWORDS,
@@ -3358,9 +3670,10 @@ static PyMethodDef gdpy_dirfile_methods[] = {
   },
   {"naliases", (PyCFunction)gdpy_dirfile_naliases, METH_VARARGS | METH_KEYWORDS,
     "naliases(field_code)\n\n"
-      "This function returns the number of aliases defined for the specified\n"
-      "field.  If field_code is valid, this will be at least one.  See\n"
-      "gd_naliases(3)."
+      /*--- handy ruler: closing quote as indicated (or earlier)---------\n" */
+      "This function returns the number of aliases defined for the\n"
+      "specified field.  If field_code is valid, this will be at least\n"
+      "one.  See gd_naliases(3)."
   },
   {"alias_target", (PyCFunction)gdpy_dirfile_aliastarget,
     METH_VARARGS | METH_KEYWORDS,
@@ -3418,7 +3731,7 @@ static PyMethodDef gdpy_dirfile_methods[] = {
 };
 
 #define DIRFILE_DOC \
-  "dirfile([name [, flags [, sehandler [, extra ]]])\n\n" \
+  "dirfile([name, flags, sehandler, extra, character_encoding])\n\n" \
 "If 'name' is omitted or None, returns an invalid dirfile, as if\n" \
 "gd_invalid_dirfile(3) were called.  Othwerwise, if 'name' is a string,\n" \
 "returns a dirfile object representing the dirfile specified by 'name'.\n" \
@@ -3432,7 +3745,6 @@ static PyMethodDef gdpy_dirfile_methods[] = {
 "providing the same information as the gd_pdata_t structure in the C API.\n"\
 "The second object is the 'extra' object passed to this constructor, and\n"\
 "may be any object desired by the caller.  If no extra parameter was\n"\
-/* ---------------------------------------------------------------------| */\
 "specified, this will be None.  The sehandler should return either:\n\n"\
 " * an integer, one of the pygetdata.SYNTAX_... symbols; or\n"\
 " * a string containing the corrected line, and pygetdata.SYNTAX_RESCAN\n"\
@@ -3441,6 +3753,12 @@ static PyMethodDef gdpy_dirfile_methods[] = {
 "   symbols, and then, optionally, a string containing the corrected\n"\
 "   line.\n"\
 "\n"\
+/* ---------------------------------------------------------------------| */\
+"The 'character_encoding' parameter sets the initial value of the\n"\
+"character_encoding attribute (q.v.).  If this parameter is omitted, the\n"\
+"initial value of the attribute is copied from the global\n"\
+"pygetdata.character_encoding instead.\n"\
+"\n"\
 "The dirfile will be automatically closed when garbage collection is run\n"\
 "on the object.  In general, however, an explicit call to close() or\n"\
 "discard() is preferable on a writeable dirfile, since the implicit close\n"\
@@ -3452,8 +3770,7 @@ static PyMethodDef gdpy_dirfile_methods[] = {
 
 PyTypeObject gdpy_dirfile =
 {
-  PyObject_HEAD_INIT(NULL)
-    0,                             /* ob_size */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "pygetdata.dirfile",             /* tp_name */
   sizeof(struct gdpy_dirfile_t),   /* tp_basicsize */
   0,                               /* tp_itemsize */
diff --git a/bindings/python/pyentry.c b/bindings/python/pyentry.c
index 4444f64..4bae1ab 100644
--- a/bindings/python/pyentry.c
+++ b/bindings/python/pyentry.c
@@ -18,8 +18,7 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#define NO_IMPORT_ARRAY
-#include "pygetdata.h"
+#include "gdpy_intern.h"
 
 static const char *gdpy_entry_type_names[] =
 {
@@ -45,24 +44,23 @@ static const char *gdpy_entry_type_names[] =
 };
 #define GDPY_N_ENTYPES 0x12
 
-static char *gdpy_dup_pystring(PyObject *obj)
-{
-  char *s;
-
-  dtrace("%p", obj);
-
-  s = PyString_AsString(obj);
-
-  if (s != NULL) {
-    s = strdup(s);
-
-    if (s == NULL)
-      PyErr_NoMemory();
-  }
-
-  dreturn("%p", s);
-  return s;
-}
+#define S1CHECK do { \
+  if (s1 == NULL) { dreturn("%p", NULL); return NULL; } \
+} while(0)
+#define S2CHECK do { \
+  if (s2 == NULL) { Py_DECREF(s1); dreturn("%p", NULL); return NULL; } \
+} while(0)
+#define S3CHECK do { \
+  if (s3 == NULL) { \
+    Py_DECREF(s1); Py_DECREF(s2); dreturn("%p", NULL); return NULL; \
+  } \
+} while(0)
+#define S4CHECK do { \
+  if (s4 == NULL) { \
+    Py_DECREF(s1); Py_DECREF(s2); Py_DECREF(s3); \
+    dreturn("%p", NULL); return NULL; \
+  } \
+} while(0)
 
 static void gdpy_entry_delete(struct gdpy_entry_t *self)
 {
@@ -70,6 +68,7 @@ static void gdpy_entry_delete(struct gdpy_entry_t *self)
 
   gd_free_entry_strings(self->E);
   free(self->E);
+  free(self->char_enc);
   PyObject_Del(self);
 
   dreturnvoid();
@@ -86,73 +85,65 @@ static PyObject *gdpy_entry_create(PyTypeObject *type, PyObject *args,
 
   if (self) {
     self->E = NULL;
+    self->char_enc = gdpy_copy_global_charenc();
   }
 
   dreturn("%p", self);
   return (PyObject*)self;
 }
 
-static void gdpy_set_scalar_from_pyobj(PyObject *pyobj, gd_type_t type,
-    char **scalar, void *data)
+static PyObject *gdpyobj_from_scalar(const gd_entry_t *E, int i, gd_type_t type,
+    const void *value, const char *char_enc)
 {
-  dtrace("%p, %x, %p, %p", pyobj, type, scalar, data);
-  /* FIXME */
+  PyObject *pyobj;
+  dtrace("%p, %i, 0x%X, %p, %p\n", E, i, type, value, char_enc);
+
+  if (E->scalar[i]) {
+    /* Return the scalar field code */
+    if (E->scalar_ind[i] >= 0) {
+      char *buffer = malloc(strlen(E->scalar[i]) + 23);
+      if (buffer == NULL) {
+        PyErr_NoMemory();
+        dreturn("%p", NULL);
+        return NULL;
+      }
+      sprintf(buffer, "%s<%i>", E->scalar[i], E->scalar_ind[i]);
+      pyobj = gdpyobj_from_string(buffer, char_enc);
+      free(buffer);
+    } else
+      pyobj = gdpyobj_from_string(E->scalar[i], char_enc);
+  } else /* If scalar is NULL, return the number */
+    pyobj = gdpy_convert_to_pyobj(value, type, 0);
 
-  if (PyString_Check(pyobj))
-    *scalar = gdpy_dup_pystring(pyobj);
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+static void gdpy_set_scalar_from_pyobj(PyObject *pyobj, gd_type_t type,
+    char **scalar, const char *char_enc, void *data, const char *name)
+{
+  dtrace("%p, 0x%X, %p, %p, %p", pyobj, type, scalar, char_enc, data);
+
+  if (pyobj == NULL) {
+    if (name)
+      PyErr_Format(PyExc_TypeError, "deletion of %s", name);
+    else {
+      /* If name is NULL, the caller has taken care of setting *data to
+       * an appropriate default value, but we should still zero the scalar */
+      *scalar = NULL;
+    }
+  } else if (gdpy_encobj_check(pyobj) || PyUnicode_Check(pyobj))
+    *scalar = gdpy_string_from_pyobj(pyobj, char_enc, NULL);
   else {
     *scalar = NULL;
-    switch (type) {
-      case GD_UINT8:
-        *(uint8_t*)data = (uint8_t)PyInt_AsUnsignedLongMask(pyobj);
-        break;
-      case GD_INT8:
-        *(int8_t*)data = (int8_t)PyInt_AsLong(pyobj);
-        break;
-      case GD_UINT16:
-        *(uint16_t*)data = (uint16_t)PyInt_AsUnsignedLongMask(pyobj);
-        break;
-      case GD_INT16:
-        *(int16_t*)data = (int16_t)PyInt_AsLong(pyobj);
-        break;
-      case GD_UINT32:
-        *(uint32_t*)data = (uint32_t)PyLong_AsUnsignedLong(pyobj);
-        break;
-      case GD_INT32:
-        *(int32_t*)data = (int32_t)PyLong_AsLong(pyobj);
-        break;
-      case GD_UINT64:
-        if (PyLong_Check(pyobj))
-          *(uint64_t*)data = PyLong_AsUnsignedLongLong(pyobj);
-        else
-          *(uint64_t*)data = PyInt_AsUnsignedLongLongMask(pyobj);
-        break;
-      case GD_INT64:
-        *(int64_t*)data = (int64_t)PyLong_AsLongLong(pyobj);
-        break;
-      case GD_FLOAT32:
-        *(float*)data = (float)PyFloat_AsDouble(pyobj);
-        break;
-      case GD_FLOAT64:
-        *(double*)data = PyFloat_AsDouble(pyobj);
-        break;
-      case GD_COMPLEX64:
-        gdpy_as_complex((float*)data, pyobj);
-        break;
-      case GD_COMPLEX128:
-        gdpy_as_complex((double*)data, pyobj);
-        break;
-      default:
-        PyErr_Format(PyExc_RuntimeError,
-              "unexpected field type (%x) inside %s", type, __func__);
-    }
+    gdpy_coerce_from_pyobj(pyobj, type, data);
   }
 
   dreturnvoid();
 }
 
 static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
-    const char *name)
+    const char *char_enc, const char *name)
 {
   PyObject *parm1;
   PyObject *parm2;
@@ -161,7 +152,7 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
   int i, count, min;
   long size;
 
-  dtrace("%p, %p, \"%s\"", E, tuple, name);
+  dtrace("%p, %p, %p, \"%s\"", E, tuple, char_enc, name);
 
   switch (E->field_type)
   {
@@ -214,13 +205,14 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
   switch (E->field_type)
   {
     case GD_RAW_ENTRY:
-      E->EN(raw,data_type) = (gd_type_t)PyInt_AsLong(PyTuple_GetItem(tuple, 0));
+      E->EN(raw,data_type) =
+        (gd_type_t)gdpy_long_from_pyobj(PyTuple_GetItem(tuple, 0));
       if (GDPY_INVALID_TYPE(E->EN(raw,data_type)))
         PyErr_SetString(PyExc_ValueError,
             "'pygetdata.entry' invalid data type");
 
       gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 1), GD_UINT_TYPE,
-          &E->scalar[0], &E->EN(raw,spf));
+          &E->scalar[0], char_enc, &E->EN(raw,spf), NULL);
       break;
     case GD_LINCOM_ENTRY:
       parm1 = PyTuple_GetItem(tuple, 0);
@@ -247,7 +239,8 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
 
       for (i = 0; i < count; ++i) {
-        E->in_fields[i] = gdpy_dup_pystring(PyTuple_GetItem(parm1, i));
+        E->in_fields[i] = gdpy_string_from_pyobj(PyTuple_GetItem(parm1, i),
+            char_enc, "in_fields must be string");
 
         if (PyErr_Occurred()) {
           dreturnvoid();
@@ -260,10 +253,10 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
           gdpy_as_complex(gd_csp_(E->EN(lincom,cm)[i]), obj);
         } else if (E->flags & GD_EN_COMPSCAL)
           gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, &E->scalar[i],
-              &E->EN(lincom,cm)[i]);
+              char_enc, &E->EN(lincom,cm)[i], NULL);
         else {
-          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[i],
-              &E->EN(lincom,m)[i]);
+          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[i], char_enc,
+              &E->EN(lincom,m)[i], NULL);
           gd_rs2cs_(E->EN(lincom,cm)[i], E->EN(lincom,m)[i]);
         }
 
@@ -278,10 +271,12 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
           gdpy_as_complex(gd_csp_(E->EN(lincom,cb)[i]), obj);
         } else if (E->flags & GD_EN_COMPSCAL)
           gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128,
-              &E->scalar[i + GD_MAX_LINCOM], &E->EN(lincom,cb)[i]);
+              &E->scalar[i + GD_MAX_LINCOM], char_enc, &E->EN(lincom,cb)[i],
+              NULL);
         else {
           gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64,
-              &E->scalar[i + GD_MAX_LINCOM], &E->EN(lincom,b)[i]);
+              &E->scalar[i + GD_MAX_LINCOM], char_enc, &E->EN(lincom,b)[i],
+              NULL);
           gd_rs2cs_(E->EN(lincom,cb)[i], E->EN(lincom,b)[i]);
         }
 
@@ -292,14 +287,16 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
       break;
     case GD_LINTERP_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
         return;
       }
 
-      E->EN(linterp,table) = gdpy_dup_pystring(PyTuple_GetItem(tuple, 1));
+      E->EN(linterp,table) = gdpy_path_from_pyobj(PyTuple_GetItem(tuple, 1),
+          char_enc);
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -308,7 +305,8 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       break;
     case GD_BIT_ENTRY:
     case GD_SBIT_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -316,10 +314,10 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
 
       gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 1), GD_INT_TYPE,
-          &E->scalar[0], &E->EN(bit,bitnum));
+          &E->scalar[0], char_enc, &E->EN(bit,bitnum), NULL);
       if (size > 2)
         gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 2), GD_INT_TYPE,
-            &E->scalar[1], &E->EN(bit,numbits));
+            &E->scalar[1], char_enc, &E->EN(bit,numbits), NULL);
       else {
         E->EN(bit,numbits) = 1;
         E->scalar[1] = NULL;
@@ -327,14 +325,16 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       break;
     case GD_MULTIPLY_ENTRY:
     case GD_DIVIDE_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
         return;
       }
 
-      E->in_fields[1] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 1));
+      E->in_fields[1] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 1),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -342,7 +342,8 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
       break;
     case GD_RECIP_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -354,11 +355,11 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
         E->flags |= GD_EN_COMPSCAL;
         gdpy_as_complex(gd_csp_(E->EN(recip,cdividend)), obj);
       } else if (E->flags & GD_EN_COMPSCAL)
-        gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, &E->scalar[0],
-            &E->EN(recip,cdividend));
+        gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, &E->scalar[0], char_enc,
+            &E->EN(recip,cdividend), NULL);
       else {
-        gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[0],
-            &E->EN(recip,dividend));
+        gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[0], char_enc,
+            &E->EN(recip,dividend), NULL);
         gd_rs2cs_(E->EN(recip,cdividend), E->EN(recip,dividend));
       }
 
@@ -368,7 +369,8 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
       break;
     case GD_PHASE_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -376,7 +378,7 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
 
       gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 1), GD_INT64,
-          &E->scalar[0], &E->EN(phase,shift));
+          &E->scalar[0], char_enc, &E->EN(phase,shift), NULL);
       break;
     case GD_POLYNOM_ENTRY:
       parm2 = PyTuple_GetItem(tuple, 1);
@@ -391,7 +393,8 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       if (count > GD_MAX_POLYORD)
         count = GD_MAX_POLYORD;
 
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -406,10 +409,10 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
           E->scalar[i] = NULL;
         } else if (E->flags & GD_EN_COMPSCAL)
           gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, &E->scalar[i],
-              &E->EN(polynom,ca)[i]);
+              char_enc, &E->EN(polynom,ca)[i], NULL);
         else {
-          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[i],
-              &E->EN(polynom,a)[i]);
+          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[i], char_enc,
+              &E->EN(polynom,a)[i], NULL);
           gd_rs2cs_(E->EN(polynom,ca)[i], E->EN(polynom,a)[i]);
         }
 
@@ -420,14 +423,16 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
       break;
     case GD_WINDOW_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
         return;
       }
 
-      E->in_fields[1] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 1));
+      E->in_fields[1] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 1),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -435,7 +440,7 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
 
       E->EN(window,windop) =
-        (gd_windop_t)PyInt_AsLong(PyTuple_GetItem(tuple, 2));
+        (gd_windop_t)gdpy_long_from_pyobj(PyTuple_GetItem(tuple, 2));
       if (GDPY_INVALID_OP(E->EN(window,windop)))
         PyErr_SetString(PyExc_ValueError,
             "'pygetdata.entry' invalid window operation");
@@ -444,17 +449,17 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       switch (E->EN(window,windop)) {
         case GD_WINDOP_EQ:
         case GD_WINDOP_NE:
-          gdpy_set_scalar_from_pyobj(obj, GD_INT64, &E->scalar[0],
-              &E->EN(window,threshold).i);
+          gdpy_set_scalar_from_pyobj(obj, GD_INT64, &E->scalar[0], char_enc,
+              &E->EN(window,threshold).i, NULL);
           break;
         case GD_WINDOP_SET:
         case GD_WINDOP_CLR:
-          gdpy_set_scalar_from_pyobj(obj, GD_UINT64, &E->scalar[0],
-              &E->EN(window,threshold).u);
+          gdpy_set_scalar_from_pyobj(obj, GD_UINT64, &E->scalar[0], char_enc,
+              &E->EN(window,threshold).u, NULL);
           break;
         default:
-          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[0],
-              &E->EN(window,threshold).r);
+          gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, &E->scalar[0], char_enc,
+              &E->EN(window,threshold).r, NULL);
           break;
       }
 
@@ -464,14 +469,16 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
       break;
     case GD_MPLEX_ENTRY:
-      E->in_fields[0] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 0));
+      E->in_fields[0] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 0),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
         return;
       }
 
-      E->in_fields[1] = gdpy_dup_pystring(PyTuple_GetItem(tuple, 1));
+      E->in_fields[1] = gdpy_string_from_pyobj(PyTuple_GetItem(tuple, 1),
+          char_enc, "in_fields must be string");
 
       if (PyErr_Occurred()) {
         dreturnvoid();
@@ -479,18 +486,18 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
       }
 
       gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 2), GD_INT_TYPE,
-          &E->scalar[0], &E->EN(mplex,count_val));
+          &E->scalar[0], char_enc, &E->EN(mplex,count_val), NULL);
 
       gdpy_set_scalar_from_pyobj(PyTuple_GetItem(tuple, 3), GD_INT_TYPE,
-          &E->scalar[1], &E->EN(mplex,period));
+          &E->scalar[1], char_enc, &E->EN(mplex,period), NULL);
       break;
     case GD_CARRAY_ENTRY:
       E->EN(scalar,array_len) =
-        (size_t)PyLong_AsUnsignedLong(PyTuple_GetItem(tuple, 1));
+        (size_t)gdpy_ulong_from_pyobj(PyTuple_GetItem(tuple, 1));
       /* fallthrough */
     case GD_CONST_ENTRY:
       E->EN(scalar,const_type) =
-        (gd_type_t)PyInt_AsLong(PyTuple_GetItem(tuple, 0));
+        (gd_type_t)gdpy_long_from_pyobj(PyTuple_GetItem(tuple, 0));
       if (GDPY_INVALID_TYPE(E->EN(scalar,const_type)))
         PyErr_SetString(PyExc_ValueError,
             "'pygetdata.entry' invalid data type");
@@ -505,13 +512,13 @@ static void gdpy_set_entry_from_tuple(gd_entry_t *E, PyObject *tuple,
 }
 
 static void gdpy_set_entry_from_dict(gd_entry_t *E, PyObject *parms,
-    const char *name)
+    const char *char_enc, const char *name)
 {
   PyObject *tuple = Py_None;
   const char *key[4];
   int i, size = 0;
 
-  dtrace("%p, %p, \"%s\"", E, parms, name);
+  dtrace("%p, %p, %p, \"%s\"", E, parms, char_enc, name);
 
   /* convert the dictionary to a tuple */
 
@@ -629,7 +636,7 @@ static void gdpy_set_entry_from_dict(gd_entry_t *E, PyObject *parms,
     }
   }
 
-  gdpy_set_entry_from_tuple(E, tuple, name);
+  gdpy_set_entry_from_tuple(E, tuple, char_enc, name);
 
   dreturnvoid();
 }
@@ -638,33 +645,48 @@ static int gdpy_entry_init(struct gdpy_entry_t *self, PyObject *args,
     PyObject *keys)
 {
   gd_entry_t E;
-  char *keywords[] = {"type", "name", "fragment_index", "parameters", NULL};
+  char *keywords[] = {"type", "name", "fragment_index", "parameters",
+    "character_encoding", NULL};
   PyObject *parms = NULL;
+  PyObject *char_enc = NULL;
+  PyObject *field_name;
   int field_type;
-  const char *field_name;
 
   dtrace("%p, %p, %p", self, args, keys);
 
   memset(&E, 0, sizeof(gd_entry_t));
 
-  if (!PyArg_ParseTupleAndKeywords(args, keys, "isi|O:pygetdata.entry.__init__",
-        keywords, &field_type, &field_name, &E.fragment_index, &parms))
+  if (!PyArg_ParseTupleAndKeywords(args, keys,
+        "iOi|OO:pygetdata.entry.__init__", keywords, &field_type,
+        &field_name, &E.fragment_index, &parms, &char_enc))
   {
     dreturn("%i", -1);
     return -1;
   }
 
-  E.field_type = field_type;
-  E.field = strdup(field_name);
-  if (E.field == NULL) {
-    PyErr_NoMemory();
+  /* First, try to update character_encoding, if requested */
+  if (char_enc) {
+    if (gdpy_parse_charenc(&self->char_enc, char_enc)) {
+      dreturn("%i", -1);
+      return -1;
+    }
+  }
+
+  /* Now try to convert the field name object */
+  E.field = gdpy_string_from_pyobj(field_name, self->char_enc,
+      "field name should be string");
+
+  if (PyErr_Occurred()) {
     dreturn("%i", -1);
     return -1;
   }
 
+  E.field_type = field_type;
+
   /* check for valid field type */
   if (E.field_type > GDPY_N_ENTYPES || E.field_type <= 0 ||
-      gdpy_entry_type_names[E.field_type] == NULL) {
+      gdpy_entry_type_names[E.field_type] == NULL)
+  {
     PyErr_SetString(PyExc_ValueError,
         "'pygetdata.entry.__init__' invalid entry type");
     dreturn("%i", -1);
@@ -678,9 +700,11 @@ static int gdpy_entry_init(struct gdpy_entry_t *self, PyObject *args,
         "of %s require parameter tuple or dictionary",
         gdpy_entry_type_names[E.field_type]);
   else if (PyDict_Check(parms))
-    gdpy_set_entry_from_dict(&E, parms, "pygetdata.entry.__init__");
+    gdpy_set_entry_from_dict(&E, parms, self->char_enc,
+        "pygetdata.entry.__init__");
   else if (PyTuple_Check(parms))
-    gdpy_set_entry_from_tuple(&E, parms, "pygetdata.entry.__init__");
+    gdpy_set_entry_from_tuple(&E, parms, self->char_enc,
+        "pygetdata.entry.__init__");
   else
     PyErr_SetString(PyExc_TypeError, "pygetdata.dirfile.__init__() argument 3 "
         "must be a tuple or dictionary");
@@ -712,7 +736,7 @@ static PyObject *gdpy_entry_getname(struct gdpy_entry_t *self, void *closure)
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyString_FromString(self->E->field);
+  pyobj = gdpyobj_from_string(self->E->field, self->char_enc);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -725,7 +749,14 @@ static int gdpy_entry_setname(struct gdpy_entry_t *self, PyObject *value,
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  s = gdpy_dup_pystring(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of name is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  s = gdpy_string_from_pyobj(value, self->char_enc,
+      "field name should be string");
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -746,7 +777,7 @@ static PyObject *gdpy_entry_getfragment(struct gdpy_entry_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyInt_FromLong(self->E->fragment_index);
+  pyobj = gdpyint_fromlong(self->E->fragment_index);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -759,7 +790,13 @@ static int gdpy_entry_setfragment(struct gdpy_entry_t *self, PyObject *value,
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  t = (int)PyInt_AsLong(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of fragment is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  t = (int)gdpy_long_from_pyobj(value);
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
     return -1;
@@ -778,7 +815,7 @@ static PyObject *gdpy_entry_gettypename(struct gdpy_entry_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyString_FromString(gdpy_entry_type_names[self->E->field_type]);
+  pyobj = gdpystrobj_from_string(gdpy_entry_type_names[self->E->field_type]);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -790,7 +827,7 @@ static PyObject *gdpy_entry_gettype(struct gdpy_entry_t *self, void *closure)
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyInt_FromLong(self->E->field_type);
+  pyobj = gdpyint_fromlong(self->E->field_type);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -800,7 +837,7 @@ static PyObject *gdpy_entry_getinfields(struct gdpy_entry_t *self,
     void *closure)
 {
   int i;
-  PyObject *tuple = NULL;
+  PyObject *tuple = NULL, *s1, *s2;
 
   dtrace("%p, %p", self, closure);
 
@@ -808,8 +845,15 @@ static PyObject *gdpy_entry_getinfields(struct gdpy_entry_t *self,
   {
     case GD_LINCOM_ENTRY:
       tuple = PyTuple_New(self->E->EN(lincom,n_fields));
-      for (i = 0; i < self->E->EN(lincom,n_fields); ++i)
-        PyTuple_SetItem(tuple, i, PyString_FromString(self->E->in_fields[i]));
+      for (i = 0; i < self->E->EN(lincom,n_fields); ++i) {
+        s1 = gdpyobj_from_string(self->E->in_fields[i], self->char_enc);
+        if (s1 == NULL) {
+          Py_DECREF(tuple);
+          dreturn("%p", NULL);
+          return NULL;
+        }
+        PyTuple_SetItem(tuple, i, s1);
+      }
       break;
     case GD_LINTERP_ENTRY:
     case GD_BIT_ENTRY:
@@ -817,14 +861,20 @@ static PyObject *gdpy_entry_getinfields(struct gdpy_entry_t *self,
     case GD_POLYNOM_ENTRY:
     case GD_SBIT_ENTRY:
     case GD_RECIP_ENTRY:
-      tuple = Py_BuildValue("(s)", self->E->in_fields[0]);
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      tuple = Py_BuildValue("(N)", s1);
+      S1CHECK;
       break;
     case GD_MULTIPLY_ENTRY:
     case GD_DIVIDE_ENTRY:
     case GD_WINDOW_ENTRY:
     case GD_MPLEX_ENTRY:
-      tuple = Py_BuildValue("(ss)", self->E->in_fields[0],
-          self->E->in_fields[1]);
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_string(self->E->in_fields[1], self->char_enc);
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s1, s2);
       break;
     case GD_NO_ENTRY:
     case GD_ALIAS_ENTRY:
@@ -851,9 +901,17 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
 
   dtrace("%p, %p, %p", self, value, closure);
 
+
   switch (self->E->field_type)
   {
     case GD_LINCOM_ENTRY:
+      if (value == NULL) {
+        PyErr_SetString(PyExc_TypeError,
+            "deletion of in_fields is not supported");
+        dreturn("%i", -1);
+        return -1;
+      }
+
       if (!PyTuple_Check(value)) {
         PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
             "attribute 'in_fields' must be a tuple");
@@ -869,7 +927,8 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
       }
 
       for (i = 0; i < self->E->EN(lincom,n_fields); ++i)
-        s[i] = gdpy_dup_pystring(PyTuple_GetItem(value, i));
+        s[i] = gdpy_string_from_pyobj(PyTuple_GetItem(value, i), self->char_enc,
+            "in_fields should be strings");
 
       if (PyErr_Occurred()) {
         dreturn("%i", -1);
@@ -887,8 +946,16 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
     case GD_POLYNOM_ENTRY:
     case GD_SBIT_ENTRY:
     case GD_RECIP_ENTRY:
+      if (value == NULL) {
+        PyErr_SetString(PyExc_TypeError,
+            "deletion of in_fields is not supported");
+        dreturn("%i", -1);
+        return -1;
+      }
+
       if (!PyTuple_Check(value))
-        s[0] = gdpy_dup_pystring(value);
+        s[0] = gdpy_string_from_pyobj(value, self->char_enc,
+            "in_fields should be strings");
       else {
         if (PyTuple_Size(value) < 1) {
           PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
@@ -896,7 +963,8 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
           dreturn("%i", -1);
         }
 
-        s[0] = gdpy_dup_pystring(PyTuple_GetItem(value, 0));
+        s[0] = gdpy_string_from_pyobj(PyTuple_GetItem(value, 0), self->char_enc,
+            "in_fields should be strings");
       }
 
       if (PyErr_Occurred()) {
@@ -911,6 +979,13 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
     case GD_DIVIDE_ENTRY:
     case GD_WINDOW_ENTRY:
     case GD_MPLEX_ENTRY:
+      if (value == NULL) {
+        PyErr_SetString(PyExc_TypeError,
+            "deletion of in_fields is not supported");
+        dreturn("%i", -1);
+        return -1;
+      }
+
       if (!PyTuple_Check(value)) {
         PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
             "attribute 'in_fields' must be a tuple");
@@ -926,7 +1001,8 @@ static int gdpy_entry_setinfields(struct gdpy_entry_t *self, PyObject *value,
       }
 
       for (i = 0; i < 2; ++i)
-        s[i] = gdpy_dup_pystring(PyTuple_GetItem(value, i));
+        s[i] = gdpy_string_from_pyobj(PyTuple_GetItem(value, i), self->char_enc,
+            "in_fields should be strings");
 
       if (PyErr_Occurred()) {
         dreturn("%i", -1);
@@ -978,7 +1054,7 @@ static PyObject *gdpy_entry_getdatatypename(struct gdpy_entry_t *self,
     sprintf(buffer, "%s%i", (t & GD_COMPLEX) ? "COMPLEX" :
         (t & GD_IEEE754) ? "FLOAT" : (t & GD_SIGNED) ? "INT" : "UINT",
         8 * GD_SIZE(t));
-    obj = PyString_FromString(buffer);
+    obj = gdpystrobj_from_string(buffer);
   }
 
   dreturn("%p", obj);
@@ -993,10 +1069,10 @@ static PyObject *gdpy_entry_getdatatype(struct gdpy_entry_t *self,
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_RAW_ENTRY)
-    obj = PyInt_FromLong(self->E->EN(raw,data_type));
+    obj = gdpyint_fromlong(self->E->EN(raw,data_type));
   else if (self->E->field_type == GD_CONST_ENTRY ||
       self->E->field_type == GD_CARRAY_ENTRY)
-    obj = PyInt_FromLong(self->E->EN(scalar,const_type));
+    obj = gdpyint_fromlong(self->E->EN(scalar,const_type));
   else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'data_type' not available for entry type %s",
@@ -1024,7 +1100,13 @@ static int gdpy_entry_setdatatype(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  t = PyInt_AsLong(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of data_type is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  t = gdpy_long_from_pyobj(value);
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
     return -1;
@@ -1053,12 +1135,10 @@ static PyObject *gdpy_entry_getspf(struct gdpy_entry_t *self, void *closure)
 
   dtrace("%p, %p", self, closure);
 
-  if (self->E->field_type == GD_RAW_ENTRY) {
-    if (self->E->scalar[0] == NULL)
-      obj = PyInt_FromLong(self->E->EN(raw,spf));
-    else
-      obj = PyString_FromString(self->E->scalar[0]);
-  } else
+  if (self->E->field_type == GD_RAW_ENTRY)
+    obj = gdpyobj_from_scalar(self->E, 0, GD_UINT_TYPE, &self->E->EN(raw,spf),
+        self->char_enc);
+  else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'spf' not available for entry type %s",
         gdpy_entry_type_names[self->E->field_type]);
@@ -1083,7 +1163,8 @@ static int gdpy_entry_setspf(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_UINT_TYPE, &scalar, &spf);
+  gdpy_set_scalar_from_pyobj(value, GD_UINT_TYPE, &scalar, self->char_enc,
+      &spf, "spf");
 
   if (PyErr_Occurred()) {
     free(scalar);
@@ -1132,7 +1213,13 @@ static int gdpy_entry_setarraylen(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  array_len = PyLong_AsUnsignedLong(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of array_len is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  array_len = gdpy_ulong_from_pyobj(value);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -1152,7 +1239,7 @@ static PyObject *gdpy_entry_getnfields(struct gdpy_entry_t *self, void *closure)
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_LINCOM_ENTRY) {
-    obj = PyInt_FromLong(self->E->EN(lincom,n_fields));
+    obj = gdpyint_fromlong(self->E->EN(lincom,n_fields));
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'n_fields' not available for entry type %s",
@@ -1177,7 +1264,13 @@ static int gdpy_entry_setnfields(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  n = (int)PyInt_AsLong(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of n_fields is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  n = (int)gdpy_long_from_pyobj(value);
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
     return -1;
@@ -1213,12 +1306,16 @@ static PyObject *gdpy_entry_getm(struct gdpy_entry_t *self, void *closure)
 
   if (self->E->field_type == GD_LINCOM_ENTRY) {
     obj = PyTuple_New(self->E->EN(lincom,n_fields));
-    for (i = 0; i < self->E->EN(lincom,n_fields); ++i)
-      PyTuple_SetItem(obj, i, (self->E->scalar[i] == NULL) ?
-          (self->E->flags & GD_EN_COMPSCAL) ?
-          gdpy_from_complex(self->E->EN(lincom,cm)[i]) :
-          PyFloat_FromDouble(self->E->EN(lincom,m)[i]) :
-          PyString_FromString(self->E->scalar[i]));
+    for (i = 0; i < self->E->EN(lincom,n_fields); ++i) {
+      PyObject *scalar = gdpyobj_from_scalar(self->E, i, GD_COMPLEX128,
+          &self->E->EN(lincom,cm)[i], self->char_enc);
+      if (scalar == NULL) {
+        Py_DECREF(obj);
+        obj = NULL;
+        break;
+      }
+      PyTuple_SetItem(obj, i, scalar);
+    }
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'm' not available for entry type %s",
@@ -1247,6 +1344,12 @@ static int gdpy_entry_setm(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of m is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
   if (!PyTuple_Check(value)) {
     PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
         "attribute 'm' must be a tuple");
@@ -1269,10 +1372,12 @@ static int gdpy_entry_setm(struct gdpy_entry_t *self, PyObject *value,
       m[i] = creal(cm[i]);
       scalar[i] = NULL;
     } else if (comp_scal) {
-      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i, cm + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i, self->char_enc,
+          cm + i, NULL);
       m[i] = creal(cm[i]);
     } else {
-      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, m + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, self->char_enc,
+          m + i, NULL);
       gd_rs2cs_(cm[i], m[i]);
     }
   }
@@ -1308,12 +1413,16 @@ static PyObject *gdpy_entry_getb(struct gdpy_entry_t *self, void *closure)
 
   if (self->E->field_type == GD_LINCOM_ENTRY) {
     obj = PyTuple_New(self->E->EN(lincom,n_fields));
-    for (i = 0; i < self->E->EN(lincom,n_fields); ++i)
-      PyTuple_SetItem(obj, i, (self->E->scalar[i + GD_MAX_LINCOM] == NULL) ?
-          (self->E->flags & GD_EN_COMPSCAL) ?
-          gdpy_from_complex(self->E->EN(lincom,cb)[i]) :
-          PyFloat_FromDouble(self->E->EN(lincom,b)[i]) :
-          PyString_FromString(self->E->scalar[i + GD_MAX_LINCOM]));
+    for (i = 0; i < self->E->EN(lincom,n_fields); ++i) {
+      PyObject *scalar = gdpyobj_from_scalar(self->E, i + GD_MAX_LINCOM,
+          GD_COMPLEX128, &self->E->EN(lincom,cb)[i], self->char_enc);
+      if (scalar == NULL) {
+        Py_DECREF(obj);
+        obj = NULL;
+        break;
+      }
+      PyTuple_SetItem(obj, i, scalar);
+    }
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'b' not available for entry type %s",
@@ -1342,6 +1451,12 @@ static int gdpy_entry_setb(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of b is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
   if (!PyTuple_Check(value)) {
     PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
         "attribute 'b' must be a tuple");
@@ -1364,10 +1479,12 @@ static int gdpy_entry_setb(struct gdpy_entry_t *self, PyObject *value,
       b[i] = creal(cb[i]);
       scalar[i] = NULL;
     } else if (comp_scal) {
-      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i, cb + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i, self->char_enc,
+          cb + i, NULL);
       b[i] = creal(cb[i]);
     } else {
-      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, b + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, self->char_enc,
+          b + i, NULL);
       gd_rs2cs_(cb[i], b[i]);
     }
   }
@@ -1401,7 +1518,7 @@ static PyObject *gdpy_entry_gettable(struct gdpy_entry_t *self, void *closure)
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_LINTERP_ENTRY)
-    obj = PyString_FromString(self->E->EN(linterp,table));
+    obj = gdpyobj_from_path(self->E->EN(linterp,table));
   else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'table' not available for entry type %s",
@@ -1414,19 +1531,11 @@ static PyObject *gdpy_entry_gettable(struct gdpy_entry_t *self, void *closure)
 static int gdpy_entry_settable(struct gdpy_entry_t *self, PyObject *value,
     void *closure)
 {
-  dtrace("%p, %p, %p", self, value, closure);
-
-  if (self->E->field_type == GD_LINTERP_ENTRY) {
-    char *s = gdpy_dup_pystring(value);
+  char *s;
 
-    if (PyErr_Occurred()) {
-      dreturn("%i", -1);
-      return -1;
-    }
+  dtrace("%p, %p, %p", self, value, closure);
 
-    free(self->E->EN(linterp,table));
-    self->E->EN(linterp,table) = s;
-  } else {
+  if (self->E->field_type != GD_LINTERP_ENTRY) {
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'table' not available for entry type %s",
         gdpy_entry_type_names[self->E->field_type]);
@@ -1434,6 +1543,22 @@ static int gdpy_entry_settable(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of table is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  s = gdpy_path_from_pyobj(value, self->char_enc);
+
+  if (PyErr_Occurred()) {
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  free(self->E->EN(linterp,table));
+  self->E->EN(linterp,table) = s;
+
   dreturn("%i", 0);
   return 0;
 }
@@ -1447,10 +1572,8 @@ static PyObject *gdpy_entry_getbitnum(struct gdpy_entry_t *self, void *closure)
   if (self->E->field_type == GD_BIT_ENTRY ||
       self->E->field_type == GD_SBIT_ENTRY)
   {
-    if (self->E->scalar[0] == NULL)
-      obj = PyInt_FromLong(self->E->EN(bit,bitnum));
-    else
-      obj = PyString_FromString(self->E->scalar[0]);
+    obj = gdpyobj_from_scalar(self->E, 0, GD_INT_TYPE, &self->E->EN(bit,bitnum),
+        self->char_enc);
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'bitnum' not available for entry type %s",
@@ -1477,7 +1600,8 @@ static int gdpy_entry_setbitnum(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, &bitnum);
+  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, self->char_enc,
+      &bitnum, "bitnum");
   if (PyErr_Occurred()) {
     free(scalar);
     dreturn("%i", -1);
@@ -1501,10 +1625,8 @@ static PyObject *gdpy_entry_getnumbits(struct gdpy_entry_t *self, void *closure)
   if (self->E->field_type == GD_BIT_ENTRY ||
       self->E->field_type == GD_SBIT_ENTRY)
   {
-    if (self->E->scalar[1] == NULL)
-      obj = PyInt_FromLong(self->E->EN(bit,numbits));
-    else
-      obj = PyString_FromString(self->E->scalar[1]);
+    obj = gdpyobj_from_scalar(self->E, 1, GD_INT_TYPE,
+        &self->E->EN(bit,numbits), self->char_enc);
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'numbits' not available for entry type %s",
@@ -1517,7 +1639,7 @@ static PyObject *gdpy_entry_getnumbits(struct gdpy_entry_t *self, void *closure)
 static int gdpy_entry_setnumbits(struct gdpy_entry_t *self, PyObject *value,
     void *closure)
 {
-  int numbits = 0;
+  int numbits = 1; /* del x.numbits <==> x.numbits=1 */
   char *scalar;
 
   dtrace("%p, %p, %p", self, value, closure);
@@ -1532,7 +1654,8 @@ static int gdpy_entry_setnumbits(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, &numbits);
+  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, self->char_enc,
+      &numbits, NULL);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -1554,14 +1677,10 @@ static PyObject *gdpy_entry_getdividend(struct gdpy_entry_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  if (self->E->field_type == GD_RECIP_ENTRY) {
-    if (self->E->scalar[0])
-      obj = PyString_FromString(self->E->scalar[0]);
-    else if (self->E->flags & GD_EN_COMPSCAL)
-      obj = gdpy_from_complex(self->E->EN(recip,cdividend));
-    else
-      obj = PyFloat_FromDouble(self->E->EN(recip,dividend));
-  } else
+  if (self->E->field_type == GD_RECIP_ENTRY)
+    obj = gdpyobj_from_scalar(self->E, 0, GD_COMPLEX128,
+        &self->E->EN(recip,cdividend), self->char_enc);
+  else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'dividend' not available for entry type %s",
         gdpy_entry_type_names[self->E->field_type]);
@@ -1590,14 +1709,25 @@ static int gdpy_entry_setdividend(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  if (PyComplex_Check(value) || PyString_Check(value))
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of dividend is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  if (PyComplex_Check(value) || PyUnicode_Check(value) ||
+      gdpy_encobj_check(value))
+  {
     comp_scal = GD_EN_COMPSCAL;
+  }
 
   if (comp_scal) {
-    gdpy_set_scalar_from_pyobj(value, GD_COMPLEX128, &scalar, &cdividend);
+    gdpy_set_scalar_from_pyobj(value, GD_COMPLEX128, &scalar, self->char_enc,
+        &cdividend, NULL);
     dividend = creal(cdividend);
   } else {
-    gdpy_set_scalar_from_pyobj(value, GD_FLOAT64, &scalar, &dividend);
+    gdpy_set_scalar_from_pyobj(value, GD_FLOAT64, &scalar, self->char_enc,
+        &dividend, NULL);
     gd_rs2cs_(cdividend, dividend);
   }
 
@@ -1623,10 +1753,8 @@ static PyObject *gdpy_entry_getshift(struct gdpy_entry_t *self, void *closure)
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_PHASE_ENTRY) {
-    if (self->E->scalar[0] == NULL)
-      obj = PyLong_FromLongLong((PY_LONG_LONG)self->E->EN(phase,shift));
-    else
-      obj = PyString_FromString(self->E->scalar[0]);
+    obj = gdpyobj_from_scalar(self->E, 0, GD_INT64, &self->E->EN(phase,shift),
+        self->char_enc);
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'shift' not available for entry type %s",
@@ -1652,7 +1780,8 @@ static int gdpy_entry_setshift(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_INT64, &scalar, &shift);
+  gdpy_set_scalar_from_pyobj(value, GD_INT64, &scalar, self->char_enc, &shift,
+      "shift");
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -1675,10 +1804,8 @@ static PyObject *gdpy_entry_getcountval(struct gdpy_entry_t *self,
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_MPLEX_ENTRY) {
-    if (self->E->scalar[0] == NULL)
-      obj = PyInt_FromLong(self->E->EN(mplex,count_val));
-    else
-      obj = PyString_FromString(self->E->scalar[0]);
+    obj = gdpyobj_from_scalar(self->E, 0, GD_INT_TYPE,
+        &self->E->EN(mplex,count_val), self->char_enc);
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'count_val' not available for entry type %s",
@@ -1704,7 +1831,8 @@ static int gdpy_entry_setcountval(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, &count_val);
+  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, self->char_enc,
+      &count_val, "count_val");
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -1727,10 +1855,8 @@ static PyObject *gdpy_entry_getperiod(struct gdpy_entry_t *self,
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_MPLEX_ENTRY) {
-    if (self->E->scalar[0] == NULL)
-      obj = PyInt_FromLong(self->E->EN(mplex,period));
-    else
-      obj = PyString_FromString(self->E->scalar[0]);
+    obj = gdpyobj_from_scalar(self->E, 1, GD_INT_TYPE,
+        &self->E->EN(mplex,period), self->char_enc);
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'period' not available for entry type %s",
@@ -1743,7 +1869,7 @@ static PyObject *gdpy_entry_getperiod(struct gdpy_entry_t *self,
 static int gdpy_entry_setperiod(struct gdpy_entry_t *self, PyObject *value,
     void *closure)
 {
-  int period = 0;
+  int period = 0; /* del x.period <==> x.period=0 */
   char *scalar;
 
   dtrace("%p, %p, %p", self, value, closure);
@@ -1756,7 +1882,8 @@ static int gdpy_entry_setperiod(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, &period);
+  gdpy_set_scalar_from_pyobj(value, GD_INT_TYPE, &scalar, self->char_enc,
+      &period, NULL);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -1780,12 +1907,16 @@ static PyObject *gdpy_entry_geta(struct gdpy_entry_t *self, void *closure)
 
   if (self->E->field_type == GD_POLYNOM_ENTRY) {
     obj = PyTuple_New(self->E->EN(polynom,poly_ord) + 1);
-    for (i = 0; i <= self->E->EN(polynom,poly_ord); ++i)
-      PyTuple_SetItem(obj, i, (self->E->scalar[i] == NULL) ?
-          (self->E->flags & GD_EN_COMPSCAL) ?
-          gdpy_from_complex(self->E->EN(polynom,ca)[i]) :
-          PyFloat_FromDouble(self->E->EN(polynom,a)[i]) :
-          PyString_FromString(self->E->scalar[i]));
+    for (i = 0; i <= self->E->EN(polynom,poly_ord); ++i) {
+      PyObject *scalar = gdpyobj_from_scalar(self->E, i, GD_COMPLEX128,
+          &self->E->EN(lincom,ca)[i], self->char_enc);
+      if (scalar == NULL) {
+        Py_DECREF(obj);
+        obj = NULL;
+        break;
+      }
+      PyTuple_SetItem(obj, i, scalar);
+    }
   } else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'a' not available for entry type %s",
@@ -1814,6 +1945,12 @@ static int gdpy_entry_seta(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of a is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
   if (!PyTuple_Check(value)) {
     PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
         "attribute 'a' must be a tuple");
@@ -1836,10 +1973,12 @@ static int gdpy_entry_seta(struct gdpy_entry_t *self, PyObject *value,
       a[i] = creal(ca[i]);
       scalar[i] = NULL;
     } else if (comp_scal) {
-      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i, ca + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_COMPLEX128, scalar + i,
+          self->char_enc, ca + i, NULL);
       a[i] = creal(ca[i]);
     } else {
-      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, a + i);
+      gdpy_set_scalar_from_pyobj(obj, GD_FLOAT64, scalar + i, self->char_enc,
+          a + i, NULL);
       gd_rs2cs_(ca[i], a[i]);
     }
   }
@@ -1868,7 +2007,7 @@ static PyObject *gdpy_entry_getpolyord(struct gdpy_entry_t *self, void *closure)
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_POLYNOM_ENTRY)
-    obj = PyInt_FromLong(self->E->EN(polynom,poly_ord));
+    obj = gdpyint_fromlong(self->E->EN(polynom,poly_ord));
   else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'poly_ord' not available for entry type %s",
@@ -1893,6 +2032,12 @@ static int gdpy_entry_setpolyord(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of poly_ord is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
   n = (int)PyLong_AsUnsignedLongLong(value);
 
   if (PyErr_Occurred()) {
@@ -1914,7 +2059,7 @@ static int gdpy_entry_setpolyord(struct gdpy_entry_t *self, PyObject *value,
 static PyObject *gdpy_entry_getparms(struct gdpy_entry_t *self, void *closure)
 {
   int i;
-  PyObject *a, *tuple = NULL;
+  PyObject *s1, *s2, *s3, *s4, *tuple = NULL;
 
   dtrace("%p, %p", self, closure);
 
@@ -1934,114 +2079,121 @@ static PyObject *gdpy_entry_getparms(struct gdpy_entry_t *self, void *closure)
           self->E->EN(scalar,array_len));
       break;
     case GD_RAW_ENTRY:
-      tuple = Py_BuildValue("(iI)", self->E->EN(raw,data_type),
-          self->E->EN(raw,spf));
+      s1 = gdpyobj_from_scalar(self->E, 0, GD_UINT_TYPE, &self->E->EN(raw,spf),
+          self->char_enc);
+      S1CHECK;
+      tuple = Py_BuildValue("(iN)", self->E->EN(raw,data_type), s1);
       break;
     case GD_LINTERP_ENTRY:
-      tuple = Py_BuildValue("(ss)", self->E->in_fields[0],
-          self->E->EN(linterp,table));
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_path(self->E->EN(linterp,table));
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s1, s2);
       break;
     case GD_MULTIPLY_ENTRY:
     case GD_DIVIDE_ENTRY:
-      tuple = Py_BuildValue("(ss)", self->E->in_fields[0],
-          self->E->in_fields[1]);
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_string(self->E->in_fields[1], self->char_enc);
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s1, s2);
       break;
     case GD_RECIP_ENTRY:
-      if (self->E->flags & GD_EN_COMPSCAL)
-        tuple = Py_BuildValue("(sO)", self->E->in_fields[0],
-            gdpy_from_complex(self->E->EN(recip,cdividend)));
-      else
-        tuple = Py_BuildValue("(sd)", self->E->in_fields[0],
-            self->E->EN(recip,dividend));
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_scalar(self->E, 0, GD_COMPLEX128,
+          &self->E->EN(recip,cdividend), self->char_enc);
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s1, s2);
       break;
     case GD_PHASE_ENTRY:
-      tuple = Py_BuildValue("(si)", self->E->in_fields[0],
-          self->E->EN(phase,shift));
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_scalar(self->E, 0, GD_INT64, &self->E->EN(phase,shift),
+            self->char_enc);
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s1, s2);
       break;
     case GD_POLYNOM_ENTRY:
-      a = PyTuple_New(self->E->EN(polynom,poly_ord) + 1);
-      if (self->E->flags & GD_EN_COMPSCAL)
-        for (i = 0; i <= self->E->EN(polynom,poly_ord); ++i)
-          PyTuple_SetItem(a, i, gdpy_from_complex(self->E->EN(polynom,ca)[i]));
-      else
-        for (i = 0; i <= self->E->EN(polynom,poly_ord); ++i)
-          PyTuple_SetItem(a, i, PyFloat_FromDouble(self->E->EN(polynom,a)[i]));
-      tuple = Py_BuildValue("(sO)", self->E->in_fields[0], a);
+      s1 = PyTuple_New(self->E->EN(polynom,poly_ord) + 1);
+      for (i = 0; i <= self->E->EN(polynom,poly_ord); ++i) {
+        s2 = gdpyobj_from_scalar(self->E, i, GD_COMPLEX128,
+            &self->E->EN(polynom,ca)[i], self->char_enc);
+        S2CHECK;
+        PyTuple_SetItem(s1, i, s2);
+      }
+      s2 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S2CHECK;
+      tuple = Py_BuildValue("(NN)", s2, s1);
       break;
     case GD_LINCOM_ENTRY:
-      switch (self->E->EN(lincom,n_fields)) {
-        case 1:
-          if (self->E->flags & GD_EN_COMPSCAL)
-            tuple = Py_BuildValue("((s)(O)(O))", self->E->in_fields[0],
-                gdpy_from_complex(self->E->EN(lincom,cm)[0]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[0]));
-          else
-            tuple = Py_BuildValue("((s)(d)(d))", self->E->in_fields[0],
-                self->E->EN(lincom,m)[0], self->E->EN(lincom,b)[0]);
-          break;
-        case 2:
-          if (self->E->flags & GD_EN_COMPSCAL)
-            tuple = Py_BuildValue("((ss)(OO)(OO))", self->E->in_fields[0],
-                self->E->in_fields[1],
-                gdpy_from_complex(self->E->EN(lincom,cm)[0]),
-                gdpy_from_complex(self->E->EN(lincom,cm)[1]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[0]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[1]));
-          else
-            tuple = Py_BuildValue("((ss)(dd)(dd))", self->E->in_fields[0],
-                self->E->in_fields[1], self->E->EN(lincom,m)[0],
-                self->E->EN(lincom,m)[1], self->E->EN(lincom,b)[0],
-                self->E->EN(lincom,b)[1]);
-          break;
-        case 3:
-          if (self->E->flags & GD_EN_COMPSCAL)
-            tuple = Py_BuildValue("((sss)(OOO)(OOO))", self->E->in_fields[0],
-                self->E->in_fields[1], self->E->in_fields[2],
-                gdpy_from_complex(self->E->EN(lincom,cm)[0]),
-                gdpy_from_complex(self->E->EN(lincom,cm)[1]),
-                gdpy_from_complex(self->E->EN(lincom,cm)[2]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[0]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[1]),
-                gdpy_from_complex(self->E->EN(lincom,cb)[2]));
-          else
-            tuple = Py_BuildValue("((sss)(ddd)(ddd))", self->E->in_fields[0],
-                self->E->in_fields[1], self->E->in_fields[2],
-                self->E->EN(lincom,m)[0], self->E->EN(lincom,m)[1],
-                self->E->EN(lincom,m)[2], self->E->EN(lincom,b)[0],
-                self->E->EN(lincom,b)[1], self->E->EN(lincom,b)[2]);
-          break;
+      s1 = PyTuple_New(self->E->EN(lincom,n_fields));
+      s2 = PyTuple_New(self->E->EN(lincom,n_fields));
+      s3 = PyTuple_New(self->E->EN(lincom,n_fields));
+      for (i = 0; i < self->E->EN(lincom,n_fields); ++i) {
+        s4 = gdpyobj_from_string(self->E->in_fields[i], self->char_enc);
+        S4CHECK;
+        PyTuple_SetItem(s1, i, s4);
+        s4 = gdpyobj_from_scalar(self->E, i, GD_COMPLEX128,
+            &self->E->EN(lincom,cm)[i], self->char_enc);
+        S4CHECK;
+        PyTuple_SetItem(s2, i, s4);
+        s4 = gdpyobj_from_scalar(self->E, i + GD_MAX_LINCOM, GD_COMPLEX128,
+            &self->E->EN(lincom,cb)[i], self->char_enc);
+        S4CHECK;
+        PyTuple_SetItem(s3, i, s4);
       }
+      tuple = Py_BuildValue("(NNN)", s1, s2, s3);
       break;
     case GD_WINDOW_ENTRY:
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_string(self->E->in_fields[1], self->char_enc);
+      S2CHECK;
       switch (self->E->EN(window,windop)) {
         case GD_WINDOP_EQ:
         case GD_WINDOP_NE:
-          tuple = Py_BuildValue("(ssiL)", self->E->in_fields[0],
-              self->E->in_fields[1], self->E->EN(window,windop),
-              (PY_LONG_LONG)self->E->EN(window,threshold).i);
+          s3 = gdpyobj_from_scalar(self->E, 0, GD_INT64,
+              &self->E->EN(window,threshold).i, self->char_enc);
           break;
         case GD_WINDOP_SET:
         case GD_WINDOP_CLR:
-          tuple = Py_BuildValue("(ssiK)", self->E->in_fields[0],
-              self->E->in_fields[1], self->E->EN(window,windop),
-              (unsigned PY_LONG_LONG)self->E->EN(window,threshold).u);
+          s3 =gdpyobj_from_scalar(self->E, 0, GD_UINT64,
+              &self->E->EN(window,threshold).u, self->char_enc);
           break;
         default:
-          tuple = Py_BuildValue("(ssid)", self->E->in_fields[0],
-              self->E->in_fields[1], self->E->EN(window,windop),
-              self->E->EN(window,threshold).r);
+          s3 = gdpyobj_from_scalar(self->E, 0, GD_FLOAT64,
+              &self->E->EN(window,threshold).r, self->char_enc);
           break;
       }
+      S3CHECK;
+      tuple = Py_BuildValue("(NNiN)", s1, s2, self->E->EN(window,windop), s3);
       break;
     case GD_BIT_ENTRY:
     case GD_SBIT_ENTRY:
-      tuple = Py_BuildValue("(sii)", self->E->in_fields[0],
-          self->E->EN(bit,bitnum), self->E->EN(bit,numbits));
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_scalar(self->E, 0, GD_INT_TYPE,
+          &self->E->EN(bit,bitnum), self->char_enc);
+      S2CHECK;
+      s3 = gdpyobj_from_scalar(self->E, 1, GD_INT_TYPE,
+            &self->E->EN(bit,numbits), self->char_enc);
+      S3CHECK;
+      tuple = Py_BuildValue("(NNN)", s1, s2, s3);
       break;
     case GD_MPLEX_ENTRY:
-      tuple = Py_BuildValue("(ssII)", self->E->in_fields[0],
-          self->E->in_fields[1], (unsigned int)self->E->EN(mplex,count_val),
-          (unsigned int)self->E->EN(mplex,period));
+      s1 = gdpyobj_from_string(self->E->in_fields[0], self->char_enc);
+      S1CHECK;
+      s2 = gdpyobj_from_string(self->E->in_fields[1], self->char_enc);
+      S2CHECK;
+      s3 = gdpyobj_from_scalar(self->E, 0, GD_INT_TYPE,
+          &self->E->EN(mplex,count_val), self->char_enc);
+      S3CHECK;
+      s4 = gdpyobj_from_scalar(self->E, 1, GD_INT_TYPE,
+            &self->E->EN(mplex,period), self->char_enc);
+      S4CHECK;
+      tuple = Py_BuildValue("(NNNN)", s1, s2, s3, s4);
       break;
   }
 
@@ -2062,10 +2214,16 @@ static int gdpy_entry_setparms(struct gdpy_entry_t *self, PyObject *value,
   E.field_type = self->E->field_type;
   E.fragment_index = self->E->fragment_index;
 
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of parameters is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
   if (PyDict_Check(value))
-    gdpy_set_entry_from_dict(&E, value, "pygetdata.entry");
+    gdpy_set_entry_from_dict(&E, value, self->char_enc, "pygetdata.entry");
   else if (PyTuple_Check(value))
-    gdpy_set_entry_from_tuple(&E, value, "pygetdata.entry");
+    gdpy_set_entry_from_tuple(&E, value, self->char_enc, "pygetdata.entry");
   else
     PyErr_SetString(PyExc_TypeError, "'pygetdata.entry' "
         "attribute 'parameters' must be a tuple or dictionary");
@@ -2091,7 +2249,7 @@ static PyObject *gdpy_entry_getwindop(struct gdpy_entry_t *self, void *closure)
   dtrace("%p, %p", self, closure);
 
   if (self->E->field_type == GD_WINDOW_ENTRY)
-    obj = PyInt_FromLong(self->E->EN(window,windop));
+    obj = gdpyint_fromlong(self->E->EN(window,windop));
   else
     PyErr_Format(PyExc_AttributeError, "'pygetdata.entry' "
         "attribute 'windop' not available for entry type %s",
@@ -2116,7 +2274,13 @@ static int gdpy_entry_setwindop(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
-  t = PyInt_AsLong(value);
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError, "deletion of windop is not supported");
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  t = gdpy_long_from_pyobj(value);
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
     return -1;
@@ -2170,6 +2334,8 @@ static int gdpy_entry_setthreshold(struct gdpy_entry_t *self, PyObject *value,
     void *closure)
 {
   gd_triplet_t t;
+  char *scalar;
+
   dtrace("%p, %p, %p", self, value, closure);
 
   if (self->E->field_type != GD_WINDOW_ENTRY) {
@@ -2183,14 +2349,17 @@ static int gdpy_entry_setthreshold(struct gdpy_entry_t *self, PyObject *value,
   switch (self->E->EN(window,windop)) {
     case GD_WINDOP_EQ:
     case GD_WINDOP_NE:
-      t.i = PyLong_AsLongLong(value);
+      gdpy_set_scalar_from_pyobj(value, GD_INT64, &scalar, self->char_enc,
+          &t.i, "threshold");
       break;
     case GD_WINDOP_SET:
     case GD_WINDOP_CLR:
-      t.u = PyLong_AsUnsignedLongLong(value);
+      gdpy_set_scalar_from_pyobj(value, GD_UINT64, &scalar, self->char_enc,
+          &t.u, "threshold");
       break;
     default:
-      t.r = PyFloat_AsDouble(value);
+      gdpy_set_scalar_from_pyobj(value, GD_FLOAT64, &scalar, self->char_enc,
+          &t.r, "threshold");
       break;
   }
 
@@ -2199,12 +2368,81 @@ static int gdpy_entry_setthreshold(struct gdpy_entry_t *self, PyObject *value,
     return -1;
   }
 
+  free(self->E->scalar[0]);
+  self->E->scalar[0] = scalar;
   self->E->EN(window,threshold) = t;
 
   dreturn("%i", 0);
   return 0;
 }
 
+static PyObject *gdpy_entry_getcharencoding(struct gdpy_entry_t *self,
+    void *closure)
+{
+  dtrace("%p, %p", self, closure);
+
+  PyObject *pyobj = gdpy_charenc_obj(self->char_enc);
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+static int gdpy_entry_setcharencoding(struct gdpy_entry_t *self,
+    PyObject *value, void *closure)
+{
+  dtrace("%p, %p, %p", self, value, closure);
+
+  if (gdpy_parse_charenc(&self->char_enc, value)) {
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  dreturn("%i", 0);
+  return 0;
+}
+
+#if (PY_MAJOR_VERSION > 2) || (PY_MINOR_VERSION >= 6)
+static PyObject *gdpy_entry_repr(struct gdpy_entry_t *self)
+{
+  PyObject *urepr, *repr, *parms, *name;
+
+  dtrace("%p", self);
+
+  /* decode name */
+  name = gdpyobj_from_string(self->E->field, self->char_enc);
+
+  /* the parameter tuple */
+  parms = gdpy_entry_getparms(self, NULL);
+  if (PyErr_Occurred()) {
+    dreturn("%p", NULL);
+    return NULL;
+  }
+
+  /* repr-ify */
+  if (self->char_enc == NULL)
+    urepr = PyUnicode_FromFormat(
+        "pygetdata.entry(pygetdata.%s, %R, %i, %R, character_encoding=None)",
+        gdpy_entry_type_names[self->E->field_type], name,
+        self->E->fragment_index, parms);
+  else
+    urepr = PyUnicode_FromFormat(
+        "pygetdata.entry(pygetdata.%s, %R, %i, %R, character_encoding=\"%s\")",
+        gdpy_entry_type_names[self->E->field_type], name,
+        self->E->fragment_index, parms, self->char_enc);
+
+  /* now encode */
+  repr = PyUnicode_AsEncodedString(urepr, "ascii", "backslashreplace");
+  Py_DECREF(urepr);
+  Py_DECREF(name);
+  Py_DECREF(parms);
+
+  dreturn("%p", repr);
+  return repr;
+}
+#else
+#define gdpy_entry_repr NULL
+#endif
+
 static PyGetSetDef gdpy_entry_getset[] = {
   { "a", (getter)gdpy_entry_geta, (setter)gdpy_entry_seta,
     "The POLYNOM co-efficients.  A tuple of numerical and/or string data.\n"
@@ -2236,6 +2474,20 @@ static PyGetSetDef gdpy_entry_getset[] = {
       "CONST scalar field, this will be the field code of that field,\n"
       "otherwise, it will be the number itself.",
     NULL },
+  { "character_encoding", (getter)gdpy_entry_getcharencoding,
+    (setter)gdpy_entry_setcharencoding,
+    "The character encoding to use when representing Dirfile string data\n"
+      "and metadata in Python.  For entry objects created with the\n"
+      "pygetdata.entry() function, the initial value of this attribute is\n"
+      "copied from the value of the global pygetdata.character_encoding\n"
+      "at the time that the dirfile object is created, if the global value\n"
+      "is valid.  If the global pygetdata.character_encoding is invalid,\n"
+      "the initial value of this attribute is simply None.  For entry\n"
+      "objects returned by pygetdata.dirfile.entry(), the value is copied\n"
+      "from the dirfile object (which is always valid).  Subsequent changes\n"
+      "affect only this object.  See the CHARACTER STRINGS section in the\n"
+      "pygetdata module documentation for further details.",
+    NULL },
   { "const_type", (getter)gdpy_entry_getdatatype,
     (setter)gdpy_entry_setdatatype, "An alias for the data_type attribute.",
     NULL },
@@ -2262,13 +2514,13 @@ static PyGetSetDef gdpy_entry_getset[] = {
     NULL },
   { "field_type", (getter)gdpy_entry_gettype, NULL,
     "A numeric code indicating the field type.  This will be one of the\n"
-      "pygetdata.*_ENTRY symbols.  This attribute is read-only.  An entry's\n"
+      "pygetdata.*_ENTRY symbols.  This attribute is read-only: an entry's\n"
       "field type may not be changed after creation.  See also the\n"
       "field_type_name attribute for a human-readable version of this data.\n",
     NULL },
   { "field_type_name", (getter)gdpy_entry_gettypename, NULL,
     "A human-readable string indicating the field type.  This attribute\n"
-      "is read-only.  An entry's field type may not be changed after\n"
+      "is read-only: an entry's field type may not be changed after\n"
       "creation.  See also the field_type attribute for a numeric version\n"
       "of this data.\n",
     NULL },
@@ -2364,14 +2616,20 @@ static PyGetSetDef gdpy_entry_getset[] = {
 };
 
 #define ENTRY_DOC \
-  "entry(type, name, fragment_index [, parameters])\n\n"\
+  "entry(type, name, fragment_index [, parameters, character_encoding])\n\n"\
 "Returns an entry object containing the metadata for one dirfile field.\n"\
 "The field type is specified by 'type', which should be one of the\n"\
 "pygetdata.*_ENTRY symbols.  The field name is specified by 'name', and\n"\
 "'fragment_index' indicates the format file fragment which will contain\n"\
 "the specification line of this field, once the entry is added to a\n"\
 "dirfile.  To add this field to the primary format file, set\n"\
-"'fragment_index' to zero.\n\n"\
+"'fragment_index' to zero.\n"\
+"\n"\
+"The 'character_encoding' parameter sets the initial value of the\n"\
+"character_encoding attribute (q.v.).  If this parameter is omitted, the\n"\
+"default value is copied from the global pygetdata.character_encoding\n"\
+"instead.\n"\
+"\n"\
 "The 'parameters' parameter is a tuple or dictionary containing field-\n"\
 "specific metadata parameters, and must be present for all field types\n"\
 "except STRING, which has no parameters.  If a tuple, 'parameters' should\n"\
@@ -2451,8 +2709,7 @@ static PyGetSetDef gdpy_entry_getset[] = {
 "dirfile.rename() or dirfile.move() should be used.\n"
 
 PyTypeObject gdpy_entry = {
-  PyObject_HEAD_INIT(NULL)
-    0,                           /* ob_size */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "pygetdata.entry",             /* tp_name */
   sizeof(struct gdpy_entry_t),   /* tp_basicsize */
   0,                             /* tp_itemsize */
@@ -2461,7 +2718,7 @@ PyTypeObject gdpy_entry = {
   0,                             /* tp_getattr */
   0,                             /* tp_setattr */
   0,                             /* tp_compare */
-  0,                             /* tp_repr */
+  (reprfunc)gdpy_entry_repr,     /* tp_repr */
   0,                             /* tp_as_number */
   0,                             /* tp_as_sequence */
   0,                             /* tp_as_mapping */
diff --git a/bindings/python/pyfragment.c b/bindings/python/pyfragment.c
index 26baf5d..647a461 100644
--- a/bindings/python/pyfragment.c
+++ b/bindings/python/pyfragment.c
@@ -18,8 +18,7 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#define NO_IMPORT_ARRAY
-#include "pygetdata.h"
+#include "gdpy_intern.h"
 
 /* Fragment */
 static void gdpy_fragment_delete(struct gdpy_fragment_t *self)
@@ -57,7 +56,7 @@ static int gdpy_fragment_init(struct gdpy_fragment_t *self, PyObject *args,
 
   if (!PyArg_ParseTupleAndKeywords(args, keys,
         "O!i:pygetdata.fragment.__init__", keywords, &gdpy_dirfile,
-        &self->dirfile, self->n))
+        self->dirfile, self->n))
   {
     dreturn("%i", -1);
     return -1;
@@ -76,7 +75,7 @@ static PyObject *gdpy_fragment_getindex(struct gdpy_fragment_t *self,
 
   dtrace("%p, %p", self, closure);
 
-  pyobj = PyInt_FromLong(self->n);
+  pyobj = gdpyint_fromlong(self->n);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -92,9 +91,9 @@ static PyObject *gdpy_fragment_getname(struct gdpy_fragment_t *self,
 
   name = gd_fragmentname(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
-  pyobj = PyString_FromString(name);
+  pyobj = gdpyobj_from_path(name);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -110,7 +109,7 @@ static PyObject *gdpy_fragment_getencoding(struct gdpy_fragment_t *self,
 
   enc = gd_encoding(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   pyobj = PyLong_FromUnsignedLong(enc);
 
@@ -136,7 +135,7 @@ static PyObject *gdpy_fragment_setencoding(struct gdpy_fragment_t *self,
 
   gd_alter_encoding(self->dirfile->D, enc, self->n, recode);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -153,7 +152,7 @@ static PyObject *gdpy_fragment_getendianness(struct gdpy_fragment_t *self,
 
   end = gd_endianness(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   pyobj = PyLong_FromUnsignedLong(end);
 
@@ -179,7 +178,7 @@ static PyObject *gdpy_fragment_setendianness(struct gdpy_fragment_t *self,
 
   gd_alter_endianness(self->dirfile->D, end, self->n, recode);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -192,7 +191,7 @@ static PyObject *gdpy_fragment_rewrite(struct gdpy_fragment_t *self)
 
   gd_rewrite_fragment(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -209,7 +208,7 @@ static PyObject *gdpy_fragment_getoffset(struct gdpy_fragment_t *self,
 
   offset = gd_frameoffset64(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   pyobj = PyLong_FromLongLong((PY_LONG_LONG)offset);
 
@@ -236,7 +235,7 @@ static PyObject *gdpy_fragment_setoffset(struct gdpy_fragment_t *self,
   gd_alter_frameoffset64(self->dirfile->D, (gd_off64_t)offset, self->n,
       recode);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   Py_INCREF(Py_None);
   dreturn("%p", Py_None);
@@ -253,9 +252,9 @@ static PyObject *gdpy_fragment_getparent(struct gdpy_fragment_t *self,
 
   parent = gd_parent_fragment(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
-  pyobj = PyInt_FromLong(parent);
+  pyobj = gdpyint_fromlong(parent);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -271,9 +270,9 @@ static PyObject *gdpy_fragment_getprotection(struct gdpy_fragment_t *self,
 
   prot = gd_protection(self->dirfile->D, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
-  pyobj = PyInt_FromLong(prot);
+  pyobj = gdpyint_fromlong(prot);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -282,11 +281,12 @@ static PyObject *gdpy_fragment_getprotection(struct gdpy_fragment_t *self,
 static int gdpy_fragment_setprotection(struct gdpy_fragment_t *self,
     PyObject *value, void *closure)
 {
-  int p;
+  int p = GD_PROTECT_NONE;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  p = (int)PyInt_AsLong(value);
+  if (value)
+    p = (int)gdpy_long_from_pyobj(value);
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -295,7 +295,7 @@ static int gdpy_fragment_setprotection(struct gdpy_fragment_t *self,
 
   gd_alter_protection(self->dirfile->D, p, self->n);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, -1);
+  GDPY_CHECK_ERROR(self->dirfile->D, -1, self->dirfile->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -311,7 +311,7 @@ static PyObject *gdpy_fragment_getprefix(struct gdpy_fragment_t *self,
 
   gd_fragment_affixes(self->dirfile->D, self->n, &prefix, &suffix);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   free(suffix);
   if (prefix == NULL) {
@@ -320,7 +320,7 @@ static PyObject *gdpy_fragment_getprefix(struct gdpy_fragment_t *self,
     return Py_None;
   }
 
-  pyobj = PyString_FromString(prefix);
+  pyobj = gdpyobj_from_string(prefix, self->dirfile->char_enc);
   free(prefix);
 
   dreturn("%p", pyobj);
@@ -330,11 +330,26 @@ static PyObject *gdpy_fragment_getprefix(struct gdpy_fragment_t *self,
 static int gdpy_fragment_setprefix(struct gdpy_fragment_t *self,
     PyObject *value, void *closure)
 {
-  const char *prefix;
+  char *prefix;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  prefix = PyString_AsString(value);
+  if (value == NULL) {
+    if (self->n == 0) {
+      prefix = strdup("");
+      if (prefix == NULL)
+        PyErr_NoMemory();
+    } else {
+      char *suffix;
+      gd_fragment_affixes(self->dirfile->D, self->n, &prefix, &suffix);
+
+      GDPY_CHECK_ERROR(self->dirfile->D, -1, self->dirfile->char_enc);
+
+      free(suffix);
+    }
+  } else
+    prefix = gdpy_string_from_pyobj(value, self->dirfile->char_enc,
+        "prefix must be string");
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -343,7 +358,9 @@ static int gdpy_fragment_setprefix(struct gdpy_fragment_t *self,
 
   gd_alter_affixes(self->dirfile->D, self->n, prefix, NULL);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, -1);
+  free(prefix);
+
+  GDPY_CHECK_ERROR(self->dirfile->D, -1, self->dirfile->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -359,7 +376,7 @@ static PyObject *gdpy_fragment_getsuffix(struct gdpy_fragment_t *self,
 
   gd_fragment_affixes(self->dirfile->D, self->n, &prefix, &suffix);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, NULL);
+  GDPY_CHECK_ERROR(self->dirfile->D, NULL, self->dirfile->char_enc);
 
   free(prefix);
   if (suffix == NULL) {
@@ -368,7 +385,7 @@ static PyObject *gdpy_fragment_getsuffix(struct gdpy_fragment_t *self,
     return Py_None;
   }
 
-  pyobj = PyString_FromString(suffix);
+  pyobj = gdpyobj_from_string(suffix, self->dirfile->char_enc);
   free(suffix);
 
   dreturn("%p", pyobj);
@@ -378,11 +395,26 @@ static PyObject *gdpy_fragment_getsuffix(struct gdpy_fragment_t *self,
 static int gdpy_fragment_setsuffix(struct gdpy_fragment_t *self,
     PyObject *value, void *closure)
 {
-  const char *suffix;
+  char *suffix;
 
   dtrace("%p, %p, %p", self, value, closure);
 
-  suffix = PyString_AsString(value);
+  if (value == NULL) {
+    if (self->n == 0) {
+      suffix = strdup("");
+      if (suffix == NULL)
+        PyErr_NoMemory();
+    } else {
+      char *prefix;
+      gd_fragment_affixes(self->dirfile->D, self->n, &prefix, &suffix);
+
+      GDPY_CHECK_ERROR(self->dirfile->D, -1, self->dirfile->char_enc);
+
+      free(prefix);
+    }
+  } else
+    suffix = gdpy_string_from_pyobj(value, self->dirfile->char_enc,
+        "suffix must be string");
 
   if (PyErr_Occurred()) {
     dreturn("%i", -1);
@@ -391,7 +423,9 @@ static int gdpy_fragment_setsuffix(struct gdpy_fragment_t *self,
 
   gd_alter_affixes(self->dirfile->D, self->n, NULL, suffix);
 
-  PYGD_CHECK_ERROR(self->dirfile->D, -1);
+  free(suffix);
+
+  GDPY_CHECK_ERROR(self->dirfile->D, -1, self->dirfile->char_enc);
 
   dreturn("%i", 0);
   return 0;
@@ -501,8 +535,7 @@ static PyMethodDef gdpy_fragment_methods[] = {
 "error."
 
 PyTypeObject gdpy_fragment = {
-  PyObject_HEAD_INIT(NULL)
-    0,                           /* ob_size */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "pygetdata.fragment",          /* tp_name */
   sizeof(struct gdpy_fragment_t),/* tp_basicsize */
   0,                             /* tp_itemsize */
diff --git a/bindings/python/pygetdata.c b/bindings/python/pygetdata.c
index 13f21be..a69f891 100644
--- a/bindings/python/pygetdata.c
+++ b/bindings/python/pygetdata.c
@@ -18,47 +18,56 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include "pygetdata.h"
-
-static PyObject *GdPy_DirfileError;
-static const char *gdpy_exception_list[GD_N_ERROR_CODES] = {
-  NULL,
-  NULL, /* 1 */
-  "Format",
-  NULL, /* 3 */
-  "Creation",
-  "BadCode",
-  "BadType",
-  "IO",
-  NULL, /* 8 */
-  "Internal",
-  "Alloc",
-  "Range",
-  "LUT",
-  "RecurseLevel",
-  "BadDirfile",
-  "BadFieldType",
-  "AccessMode",
-  "Unsupported",
-  "UnknownEncoding",
-  "BadEntry",
-  "Duplicate",
-  "Dimension",
-  "BadIndex",
-  "BadScalar",
-  "BadReference",
-  "Protected",
-  "Deletion",
-  "Argument",
-  "Callback",
-  "Exists",
-  "UncleanDatabase",
-  "Domain",
-  NULL, /* 32 */
-  NULL, /* 33 */
-  NULL, /* 34 */
-  "Bounds",
-  "LineTooLong"
+#define GDPY_INCLUDE_NUMPY
+#include "gdpy_intern.h"
+
+static PyObject *gdpy_mod = NULL;
+
+static struct {
+  char *name;
+  char *doc;
+} gdpy_exception_list[GD_N_ERROR_CODES] = {
+  { NULL, NULL },
+  { NULL, NULL }, /* 1 */
+  { "Format", "Syntax error in Dirfile metadata (GD_E_FORMAT)." },
+  { NULL, NULL }, /* 3 */
+  { "Creation", "Unable to create a Dirfile. (GD_E_CREAT)." },
+  { "BadCode", "Bad field code. (GD_E_BAD_CODE)." },
+  { "BadType", "Bad data type. (GD_E_BAD_TYPE)." },
+  { "IO", "I/O error encountered. (GD_E_IO)." },
+  { NULL, NULL }, /* 8 */
+  { "Internal", "Internal library error (GD_E_INTERNAL_ERROR).\nPlease report "
+    "to <" PACKAGE_BUGREPORT ">" },
+  { NULL, NULL }, /* 10 -- GD_E_ALLOC.  Reported via PyErr_NoMemory() */
+  { "Range", "Invalid frame or sample number (GD_E_RANGE)." },
+  { "LUT", "Malformed LINTERP table file (GD_E_LUT)." },
+  { "RecurseLevel", "Recursion too deep (GD_E_RECURSE_LEVEL)." },
+  { "BadDirfile", "Dirfile is invalid (GD_E_BAD_DIRFILE)." },
+  { "BadFieldType", "Bad field type (GD_E_BAD_FIELD_TYPE)." },
+  { "AccessMode", "Write attempt on read-only Dirfile (GD_E_ACCMODE)." },
+  { "Unsupported",
+    "Operation not supported by current encoding scheme (GD_E_UNSUPPORTED)." },
+  { "UnknownEncoding", "Unknown encoding scheme (GD_E_UNKNOWN_ENCODING)." },
+  { "BadEntry", "Invalid entry metadata (GD_E_BAD_ENTRY)." },
+  { "Duplicate", "Duplicate field name (GD_E_DUPLICATE)." },
+  { "Dimension",
+    "Scalar field found where vector field expected. (GD_E_DIMENSION)." },
+  { "BadIndex", "Invalid Fragment index (GD_E_BAD_INDEX)." },
+  { "BadScalar", "Scalar field code not found (GD_E_BAD_SCALAR)." },
+  { "BadReference", "Bad reference field (GD_E_BAD_REFERENCE)." },
+  { "Protected", "Operation prohibited by protection level (GD_E_PROTECTED)." },
+  { "Deletion", "Error deleting field (GD_E_DELETE)." },
+  { "Argument", "Bad argument passed to function (GD_E_BAD_ARGUMENT)." },
+  { "Callback", "Bad return from parser callback (GD_E_CALLBACK)." },
+  { "Exists", "Dirfile already exists (GD_E_EXISTS)." },
+  { "UncleanDatabase",
+    "Error updating Dirfile: database is unclean (GD_E_UNCLEAN_DB)." },
+  { "Domain", "Improper domain (GD_E_DOMAIN)." },
+  { NULL, NULL }, /* 32 */
+  { NULL, NULL }, /* 33 */
+  { NULL, NULL }, /* 34 */
+  { "Bounds", "CARRAY access out-of-bounds (GD_E_BOUNDS)." },
+  { "LineTooLong", "Metadata line is too long (GD_E_LINE_TOO_LONG)." }
 };
 PyObject *gdpy_exceptions[GD_N_ERROR_CODES];
 
@@ -83,12 +92,17 @@ static struct {
   { NULL, 0}
 };
 
-/* Like PyList_Append, but steal the object's reference */
 int gdpylist_append(PyObject *list, PyObject *item)
 {
-  dtrace("%p, %p", list, item);
   int ret;
 
+  dtrace("%p, %p", list, item);
+
+  if (item == NULL) {
+    dreturn("%i", 1);
+    return 1;
+  }
+
   ret = PyList_Append(list, item);
   Py_DECREF(item);
 
@@ -96,27 +110,6 @@ int gdpylist_append(PyObject *list, PyObject *item)
   return ret;
 }
 
-/* Create an array of strings from a NULL-terminated string list */
-PyObject *gdpy_to_pystringlist(const char **list)
-{
-  PyObject *pyobj;
-  size_t i;
-
-  dtrace("%p", list);
-
-  pyobj = PyList_New(0);
-  if (pyobj)
-    for (i = 0; list[i] != NULL; ++i)
-      if (gdpylist_append(pyobj, PyString_FromString(list[i]))) {
-        Py_DECREF(pyobj);
-        pyobj = NULL;
-        break;
-      }
-
-  dreturn("%p", pyobj);
-  return pyobj;
-}
-
 int gdpy_convert_from_pyobj(PyObject *value, union gdpy_quadruple_value *data,
     gd_type_t type)
 {
@@ -125,6 +118,7 @@ int gdpy_convert_from_pyobj(PyObject *value, union gdpy_quadruple_value *data,
   dtrace("%p, %p, %02x", value, data, type);
 
   /* check value type, and figure out autotype, if needed */
+#if PY_MAJOR_VERSION < 3
   if (PyInt_Check(value)) {
     data->s = PyInt_AsLong(value);
     data_type = GDPY_INT_AS_LONG;
@@ -133,93 +127,316 @@ int gdpy_convert_from_pyobj(PyObject *value, union gdpy_quadruple_value *data,
       dreturn("%i", -1);
       return -1;
     }
-  } else if (PyLong_Check(value)) {
-    if (type == GD_UNKNOWN) {
-      /* try unsigned long long first */
-      data->u = PyLong_AsUnsignedLongLong(value);
-      data_type = GDPY_LONG_AS_ULL;
-
-      if (PyErr_Occurred()) {
-        if (PyErr_ExceptionMatches(PyExc_OverflowError)) { /* too big */
-          data->f = PyLong_AsDouble(value);
-          data_type = GDPY_LONG_AS_DOUBLE;
-
-          if (PyErr_Occurred()) {
-            dreturn("%i", -1);
-            return -1;
-          }
-        } else if (PyErr_ExceptionMatches(PyExc_TypeError)) { /* too small */
-          data->f = PyLong_AsDouble(value);
-          data_type = GDPY_LONG_AS_DOUBLE;
-
-          if (PyErr_Occurred()) {
-            if (PyErr_ExceptionMatches(PyExc_TypeError)) { /* still too small */
-              data->s = PyLong_AsLongLong(value);
-              data_type = GDPY_LONG_AS_SLL;
-
-              if (PyErr_Occurred()) {
+  } else
+#endif
+  {
+    if (PyLong_Check(value)) {
+      if (type == GD_UNKNOWN) {
+        /* try unsigned long long first */
+        data->u = PyLong_AsUnsignedLongLong(value);
+        data_type = GDPY_LONG_AS_ULL;
+
+        if (PyErr_Occurred()) {
+          if (PyErr_ExceptionMatches(PyExc_OverflowError)) { /* too big */
+            data->f = PyLong_AsDouble(value);
+            data_type = GDPY_LONG_AS_DOUBLE;
+
+            if (PyErr_Occurred()) {
+              dreturn("%i", -1);
+              return -1;
+            }
+          } else if (PyErr_ExceptionMatches(PyExc_TypeError)) { /* too small */
+            data->f = PyLong_AsDouble(value);
+            data_type = GDPY_LONG_AS_DOUBLE;
+
+            if (PyErr_Occurred()) {
+              if (PyErr_ExceptionMatches(PyExc_TypeError)) { /*still too small*/
+                data->s = PyLong_AsLongLong(value);
+                data_type = GDPY_LONG_AS_SLL;
+
+                if (PyErr_Occurred()) {
+                  dreturn("%i", -1);
+                  return -1;
+                }
+              } else { /* some other error */
                 dreturn("%i", -1);
                 return -1;
               }
-            } else { /* some other error */
-              dreturn("%i", -1);
-              return -1;
             }
+          } else { /* some other error */
+            dreturn("%i", -1);
+            return -1;
           }
-        } else { /* some other error */
+        }
+      } else if (type & GD_SIGNED) {
+        data->s = PyLong_AsLongLong(value);
+        data_type = GDPY_LONG_AS_SLL;
+
+        if (PyErr_Occurred()) {
           dreturn("%i", -1);
           return -1;
         }
-      }
-    } else if (type & GD_SIGNED) {
-      data->s = PyLong_AsLongLong(value);
-      data_type = GDPY_LONG_AS_SLL;
+      } else if (type & GD_IEEE754) {
+        data->f = PyLong_AsDouble(value);
+        data_type = GDPY_LONG_AS_DOUBLE;
 
-      if (PyErr_Occurred()) {
-        dreturn("%i", -1);
-        return -1;
+        if (PyErr_Occurred()) {
+          dreturn("%i", -1);
+          return -1;
+        }
+      } else {
+        data->u = PyLong_AsLongLong(value);
+        data_type = GDPY_LONG_AS_ULL;
+
+        if (PyErr_Occurred()) {
+          dreturn("%i", -1);
+          return -1;
+        }
       }
-    } else if (type & GD_IEEE754) {
-      data->f = PyLong_AsDouble(value);
-      data_type = GDPY_LONG_AS_DOUBLE;
+    } else if (PyFloat_Check(value)) {
+      data->f = PyFloat_AsDouble(value);
+      data_type = GDPY_FLOAT_AS_DOUBLE;
 
       if (PyErr_Occurred()) {
         dreturn("%i", -1);
         return -1;
       }
-    } else {
-      data->u = PyLong_AsLongLong(value);
-      data_type = GDPY_LONG_AS_ULL;
+    } else if (PyComplex_Check(value)) {
+      gdpy_as_complex(gd_csp_(data->c), value);
+      data_type = GDPY_COMPLEX_AS_COMPLEX;
 
       if (PyErr_Occurred()) {
         dreturn("%i", -1);
         return -1;
       }
-    }
-  } else if (PyFloat_Check(value)) {
-    data->f = PyFloat_AsDouble(value);
-    data_type = GDPY_FLOAT_AS_DOUBLE;
-
-    if (PyErr_Occurred()) {
+    } else { /* a non-numeric type */
+      PyErr_SetString(PyExc_TypeError, "a numeric type was expected");
       dreturn("%i", -1);
       return -1;
     }
-  } else if (PyComplex_Check(value)) {
-    gdpy_as_complex(gd_csp_(data->c), value);
-    data_type = GDPY_COMPLEX_AS_COMPLEX;
+  }
 
-    if (PyErr_Occurred()) {
-      dreturn("%i", -1);
-      return -1;
-    }
-  } else { /* a non-numeric type */
-    PyErr_SetString(PyExc_TypeError, "a numeric type was expected");
+  dreturn("%02x", data_type);
+  return data_type;
+}
+
+unsigned long gdpy_ulong_from_pyobj(PyObject *pyobj)
+{
+  unsigned long v = 0;
+
+  dtrace("%p", pyobj);
+
+  if (PyLong_Check(pyobj))
+    v = PyLong_AsUnsignedLong(pyobj);
+#if PY_MAJOR_VERSION < 3
+  else if (PyInt_Check(pyobj))
+    v = (unsigned long)PyInt_AsLong(pyobj);
+#endif
+  else
+    PyErr_SetString(PyExc_TypeError, "an integer type was expected");
+
+  dreturn("%lu", v);
+  return v;
+}
+
+long gdpy_long_from_pyobj(PyObject *pyobj)
+{
+  long v = 0;
+
+  dtrace("%p", pyobj);
+
+  if (PyLong_Check(pyobj))
+    v = PyLong_AsLong(pyobj);
+#if PY_MAJOR_VERSION < 3
+  else if (PyInt_Check(pyobj))
+    v = PyInt_AsLong(pyobj);
+#endif
+  else
+    PyErr_SetString(PyExc_TypeError, "an integer type was expected");
+
+  dreturn("%li", v);
+  return v;
+}
+
+/* Convert a Python string-like object to a C string, returns a malloc'd
+ * string in all cases */
+char *gdpy_string_from_pyobj(PyObject *pyobj, const char *char_enc,
+    const char *err_string)
+{
+  char *s = NULL;
+  int del_pyobj = 0;
+
+  dtrace("%p, \"%s\"", pyobj, char_enc);
+
+  if (PyUnicode_Check(pyobj)) {
+    del_pyobj = 1;
+    /* Encode string */
+    if (char_enc == NULL)
+      pyobj = PyUnicode_AsUTF8String(pyobj);
+    else
+      pyobj = PyUnicode_AsEncodedString(pyobj, char_enc, "strict");
+  } else if (!gdpy_encobj_check(pyobj)) {
+    if (err_string)
+      PyErr_SetString(PyExc_TypeError, err_string);
+    dreturn("%p", NULL);
+    return NULL;
+  }
+
+  /* now convert to python object */
+  s = gdpy_string_from_encobj(pyobj);
+
+  /* strdup */
+  if (s) {
+    s = strdup(s);
+
+    if (s == NULL)
+      PyErr_NoMemory();
+  }
+
+  if (del_pyobj)
+    Py_DECREF(pyobj);
+
+  dreturn("\"%s\"", s);
+  return s;
+}
+
+/* Return a python string, optionally decoding it */
+PyObject *gdpyobj_from_string(const char *string, const char *char_enc)
+{
+  PyObject *pyobj;
+
+  dtrace("\"%s\", %p", string, char_enc);
+
+  if (char_enc == NULL)
+    pyobj = gdpy_encobj_from_string(string); /* don't decode */
+  else
+    pyobj = PyUnicode_Decode(string, strlen(string), char_enc, "strict");
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+/* Convert a GetData error string into a Python string.  These are always
+ * first decoded, if possible, and then ASCII re-encoded, since we can't know
+ * the capabilities of the controlling tty */
+PyObject *gdpyobj_from_estring(const char* string, const char *char_enc)
+{
+  PyObject *pyobj, *unicode = NULL;
+
+  dtrace("\"%s\", %p", string, char_enc);
+
+  if (char_enc) 
+    unicode = PyUnicode_Decode(string, strlen(string), char_enc, "strict");
+
+  if (unicode) {
+    pyobj = PyUnicode_AsEncodedString(unicode, "ascii", "backslashreplace");
+    Py_DECREF(unicode);
+  } else {
+    PyErr_Clear();
+    pyobj = gdpy_encobj_from_string(string);
+  }
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+#if PY_MAJOR_VERSION >= 3
+/* In Python3, filesystem encoding from Unicode is handled specially */
+char *gdpy_path_from_pyobj_(PyObject *pyobj, int dup)
+{
+  char *s;
+
+  dtrace("%p, %i", pyobj, dup);
+
+  /* Encode */
+  if (PyUnicode_Check(pyobj))
+    pyobj = PyUnicode_EncodeFSDefault(pyobj);
+  else if (!gdpy_encobj_check(pyobj)) {
+    PyErr_SetString(PyExc_TypeError, "a path was expected");
+    dreturn("%p", NULL);
+    return NULL;
+  }
+
+  s = gdpy_string_from_encobj(pyobj);
+
+  /* strdup, if requested */
+  if (s && dup) {
+    s = strdup(s);
+
+    if (s == NULL)
+      PyErr_NoMemory();
+  }
+
+  dreturn("\"%s\"", s);
+  return s;
+}
+#endif
+
+#define GDPY_COERCE_REAL(t,p,v,d) \
+  if ((p) == GDPY_INT_AS_LONG || (p) == GDPY_LONG_AS_SLL) \
+    *((t*)(v)) = (t)(d).s; \
+  else if ((p) == GDPY_LONG_AS_ULL) \
+    *((t*)(v)) = (t)(d).u; \
+  else if ((p) == GDPY_LONG_AS_DOUBLE || (p) == GDPY_FLOAT_AS_DOUBLE) \
+    *((t*)(v)) = (t)(d).f; \
+  else \
+    *((t*)(v)) = (t)creal((d).c);
+
+#ifdef GD_NO_C99_API
+#define GDPY_COERCE_CPLX(t,p,v,d) \
+  if ((p) == GDPY_INT_AS_LONG || (p) == GDPY_LONG_AS_SLL) { \
+    ((t*)(v))[0] = (t)(d).s; ((t*)(v))[1] = 0; \
+  } else if ((p) == GDPY_LONG_AS_ULL) { \
+    ((t*)(v))[0] = (t)(d).u; ((t*)(v))[1] = 0; \
+  } else if ((p) == GDPY_LONG_AS_DOUBLE || (p) == GDPY_FLOAT_AS_DOUBLE) { \
+    ((t*)(v))[0] = (t)(d).f; ((t*)(v))[1] = 0; \
+  } else { \
+    ((t*)(v))[0] = (t)(d).c[0]; ((t*)(v))[1] = (t)(d).c[1]; \
+  }
+#else
+#define GDPY_COERCE_CPLX(t,p,v,d) \
+  if ((p) == GDPY_INT_AS_LONG || (p) == GDPY_LONG_AS_SLL) \
+    *((t _Complex*)(v)) = (t)(d).s; \
+  else if ((p) == GDPY_LONG_AS_ULL) \
+    *((t _Complex*)(v)) = (t)(d).u; \
+  else if ((p) == GDPY_LONG_AS_DOUBLE || (p) == GDPY_FLOAT_AS_DOUBLE) \
+    *((t _Complex*)(v)) = (t)(d).f; \
+  else \
+    *((t _Complex*)(v)) = (t _Complex)(d).c;
+#endif
+
+int gdpy_coerce_from_pyobj(PyObject *pyobj, gd_type_t type, void *value)
+{
+  union gdpy_quadruple_value d;
+  int conv;
+
+  dtrace("%p, 0x%X, %p", pyobj, type, value);
+  
+  conv = gdpy_convert_from_pyobj(pyobj, &d, type);
+
+  if (conv == -1) {
     dreturn("%i", -1);
     return -1;
   }
 
-  dreturn("%02x", data_type);
-  return data_type;
+  switch (type) {
+    case GD_UINT8:      GDPY_COERCE_REAL(uint8_t,  conv, value, d); break;
+    case GD_INT8:       GDPY_COERCE_REAL(int8_t,   conv, value, d); break;
+    case GD_UINT16:     GDPY_COERCE_REAL(uint16_t, conv, value, d); break;
+    case GD_INT16:      GDPY_COERCE_REAL(int16_t,  conv, value, d); break;
+    case GD_UINT32:     GDPY_COERCE_REAL(uint32_t, conv, value, d); break;
+    case GD_INT32:      GDPY_COERCE_REAL(int32_t,  conv, value, d); break;
+    case GD_UINT64:     GDPY_COERCE_REAL(uint64_t, conv, value, d); break;
+    case GD_INT64:      GDPY_COERCE_REAL(int64_t , conv, value, d); break;
+    case GD_FLOAT32:    GDPY_COERCE_REAL(float   , conv, value, d); break;
+    case GD_FLOAT64:    GDPY_COERCE_REAL(double  , conv, value, d); break;
+    case GD_COMPLEX64:  GDPY_COERCE_CPLX(float   , conv, value, d); break;
+    case GD_COMPLEX128: GDPY_COERCE_CPLX(double  , conv, value, d); break;
+    default: break;
+  }
+
+  dreturn("%i", 0);
+  return 0;
 }
 
 gd_type_t gdpy_convert_from_pylist(PyObject *value, void *data, gd_type_t type,
@@ -240,12 +457,14 @@ gd_type_t gdpy_convert_from_pylist(PyObject *value, void *data, gd_type_t type,
   }
 
   switch(data_type) {
+#if PY_MAJOR_VERSION < 3
     case GDPY_INT_AS_LONG:
       type = GD_INT32;
       *(int32_t*)data = (int32_t)tmp.s;
       for (i = 1; i < ns; ++i)
         ((int32_t*)data)[i] = (int32_t)PyInt_AsLong(PyList_GetItem(value, i));
       break;
+#endif
     case GDPY_LONG_AS_ULL: 
       type = GD_UINT64;
       *(uint64_t*)data = tmp.u;
@@ -408,6 +627,45 @@ int gdpy_npytype_from_type(gd_type_t type)
   return npytype;
 }
 
+static PyObject *gdpy_maybe_complex(double re, double im, int force)
+{
+  PyObject *pyobj;
+
+  dtrace("%g, %g, %i", re, im, force);
+
+  if (force || im)
+    pyobj = PyComplex_FromDoubles(re, im);
+  else
+    pyobj = PyFloat_FromDouble(re);
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+int gdpy_report_error(DIRFILE *D, char *char_enc)
+{
+  int e;
+  
+  dtrace("%p, \"%s\"", D, char_enc);
+
+  e = gd_error(D);
+
+  if (e == GD_E_ALLOC) {
+    PyErr_NoMemory();
+  } else if (e) {
+    char *buffer = gd_error_string(D, NULL, 0);
+    if (buffer) {
+      PyErr_SetObject(gdpy_exceptions[e], gdpyobj_from_estring(buffer,
+            char_enc));
+      free(buffer); 
+    } else
+      PyErr_NoMemory(); /* Errors with errors */
+  }
+
+  dreturn("%i", e);
+  return e;
+}
+
 PyObject *gdpy_convert_to_pylist(const void *data, gd_type_t type, size_t ns)
 {
   size_t i;
@@ -425,22 +683,25 @@ PyObject *gdpy_convert_to_pylist(const void *data, gd_type_t type, size_t ns)
   switch(type) {
     case GD_UINT8:
       for (i = 0; i < ns; ++i)
-        if (gdpylist_append(pyobj, PyInt_FromLong((long)((uint8_t*)data)[i])))
+        if (gdpylist_append(pyobj, gdpyint_fromlong((long)((uint8_t*)data)[i])))
           return NULL;
       break;
     case GD_INT8:
       for (i = 0; i < ns; ++i)
-        if (gdpylist_append(pyobj, PyInt_FromLong((long)((int8_t*)data)[i])))
+        if (gdpylist_append(pyobj, gdpyint_fromlong((long)((int8_t*)data)[i])))
           return NULL;
       break;
     case GD_UINT16:
       for (i = 0; i < ns; ++i)
-        if (gdpylist_append(pyobj, PyInt_FromLong((long)((uint16_t*)data)[i])))
+        if (gdpylist_append(pyobj,
+              gdpyint_fromlong((long)((uint16_t*)data)[i])))
+        {
           return NULL;
+        }
       break;
     case GD_INT16:
       for (i = 0; i < ns; ++i)
-        if (gdpylist_append(pyobj, PyInt_FromLong((long)((int16_t*)data)[i])))
+        if (gdpylist_append(pyobj, gdpyint_fromlong((long)((int16_t*)data)[i])))
           return NULL;
       break;
     case GD_UINT32:
@@ -451,7 +712,7 @@ PyObject *gdpy_convert_to_pylist(const void *data, gd_type_t type, size_t ns)
       break;
     case GD_INT32:
       for (i = 0; i < ns; ++i)
-        if (gdpylist_append(pyobj, PyInt_FromLong((long)((int32_t*)data)[i])))
+        if (gdpylist_append(pyobj, gdpyint_fromlong((long)((int32_t*)data)[i])))
           return NULL;
       break;
     case GD_UINT64:
@@ -496,11 +757,12 @@ PyObject *gdpy_convert_to_pylist(const void *data, gd_type_t type, size_t ns)
   return pyobj;
 }
 
-PyObject *gdpy_convert_to_pyobj(const void *data, gd_type_t type)
+PyObject *gdpy_convert_to_pyobj(const void *data, gd_type_t type,
+    int force_complex)
 {
   PyObject *pyobj = NULL;
 
-  dtrace("%p, 0x%X", data, type);
+  dtrace("%p, 0x%X, %i", data, type, force_complex);
 
   switch(type) {
     case GD_NULL:
@@ -508,22 +770,22 @@ PyObject *gdpy_convert_to_pyobj(const void *data, gd_type_t type)
       pyobj = Py_None;
       break;
     case GD_UINT8:
-      pyobj = PyInt_FromLong((long)*(uint8_t*)data);
+      pyobj = gdpyint_fromlong((long)*(uint8_t*)data);
       break;
     case GD_INT8:
-      pyobj = PyInt_FromLong((long)*(int8_t*)data);
+      pyobj = gdpyint_fromlong((long)*(int8_t*)data);
       break;
     case GD_UINT16:
-      pyobj = PyInt_FromLong((long)*(uint16_t*)data);
+      pyobj = gdpyint_fromlong((long)*(uint16_t*)data);
       break;
     case GD_INT16:
-      pyobj = PyInt_FromLong((long)*(int16_t*)data);
+      pyobj = gdpyint_fromlong((long)*(int16_t*)data);
       break;
     case GD_UINT32:
       pyobj = PyLong_FromUnsignedLong((unsigned long)*(uint32_t*)data);
       break;
     case GD_INT32:
-      pyobj = PyInt_FromLong((long)*(int32_t*)data);
+      pyobj = gdpyint_fromlong((long)*(int32_t*)data);
       break;
     case GD_UINT64:
       pyobj = PyLong_FromUnsignedLongLong(
@@ -539,10 +801,12 @@ PyObject *gdpy_convert_to_pyobj(const void *data, gd_type_t type)
       pyobj = PyFloat_FromDouble(*(double*)data);
       break;
     case GD_COMPLEX64:
-      pyobj = gdpy_from_complexp((float*)data);
+      pyobj = gdpy_maybe_complex(((float*)data)[0], ((float*)data)[1],
+          force_complex);
       break;
     case GD_COMPLEX128:
-      pyobj = gdpy_from_complexp((double*)data);
+      pyobj = gdpy_maybe_complex(((double*)data)[0], ((double*)data)[1],
+          force_complex);
       break;
     case GD_UNKNOWN: /* prevent compiler warning */
       break;
@@ -552,6 +816,73 @@ PyObject *gdpy_convert_to_pyobj(const void *data, gd_type_t type)
   return pyobj;
 }
 
+/* If value is a valid encoding (or None), free the old *char_enc and update */
+int gdpy_parse_charenc(char** char_enc, PyObject *value)
+{
+  dtrace("%p, %p", char_enc, value);
+
+  if (value == NULL || value == Py_None) {
+    free(*char_enc);
+    *char_enc = NULL;
+  } else {
+    char *new_enc = gdpy_string_from_pyobj(value, NULL,
+        "character_encoding must be string or None");
+  
+    if (PyErr_Occurred()) {
+      dreturn("%i", -1);
+      return -1;
+    }
+
+    free(*char_enc);
+    *char_enc = new_enc;
+  }
+
+  dreturn("%i", 0);
+  return 0;
+}
+
+
+/* Convert an object's character_encoding data to an appropriate Python
+ * attribute (the module global character_encoding is stored as a PyObject
+ * so we don't have to do anything about that). */
+PyObject *gdpy_charenc_obj(const char *char_enc)
+{
+  PyObject *pyobj;
+
+  dtrace("%p", char_enc);
+
+  if (char_enc == NULL) {
+    Py_INCREF(Py_None);
+    pyobj = Py_None;
+  } else
+    pyobj = gdpystrobj_from_string(char_enc);
+
+  dreturn("%p", pyobj);
+  return pyobj;
+}
+
+/* Return a copy of the current value of the global
+ * pygetdata.character_encoding, or NULL.
+ */
+char *gdpy_copy_global_charenc(void)
+{
+  PyObject *global;
+  char *char_enc;
+
+  dtracevoid();
+
+  global = PyDict_GetItemString(PyModule_GetDict(gdpy_mod),
+      "character_encoding");
+
+  if (global == NULL)
+    char_enc = NULL;
+  else
+    char_enc = gdpy_string_from_pyobj(global, NULL, NULL);
+
+  dreturn("\"%s\"", char_enc);
+  return char_enc;
+}
+
 static PyObject *gdpy_encoding_support(struct gdpy_fragment_t *self,
     PyObject *args, PyObject *keys)
 {
@@ -577,7 +908,7 @@ static PyObject *gdpy_encoding_support(struct gdpy_fragment_t *self,
     return Py_None;
   }
 
-  pyobj = PyInt_FromLong(n);
+  pyobj = gdpyint_fromlong(n);
 
   dreturn("%p", pyobj);
   return pyobj;
@@ -597,121 +928,196 @@ static PyMethodDef GetDataMethods[] = {
   { NULL, NULL, 0, NULL }
 };
 
-PyMODINIT_FUNC initpygetdata(void)
+/* Documentation differences between Python2 and Python3 */
+#if PY_MAJOR_VERSION >= 3
+#define GDPY_MODULE_DOC23(two,three) three
+#else
+#define GDPY_MODULE_DOC23(two,three) two
+#endif
+
+#define GDPY_MODULE_DOC \
+  "Bindings to the GetData library for Dirfile access\n" \
+"\n" \
+"This module provides interfaces to the C GetData library.  It defines\n" \
+"three main classes:\n" \
+"\n" \
+"  o dirfile, encapsulating the C API's DIRFILE object,\n" \
+"  o entry, encapsulating the C API's gd_entry_t object, and\n" \
+"  o fragment, containing fragment metadata.\n" \
+"\n" \
+"Second, it defines various symbolic constants defined by the C API.\n" \
+"These symbols are identical to the C API's symbols, except lacking the\n" \
+"GD_ prefix.  So, for example, the C API's GD_INT8 is available in these\n" \
+"bindings as pygetdata.INT8.\n" \
+"\n" \
+"Finally, it defines a number of exceptions corresponding to C API\n" \
+"dirfile error codes.  These exceptions have similar names to the C API's\n" \
+"names, so, for example, pygetdata.BadCodeError corresponds to the C\n"\
+"API's GD_E_BAD_CODE error code.  Excluding pygetdata.AllocError, which\n"\
+/*---- handy ruler: closing quote as indicated (or earlier)--------------\n" */\
+"is simply an alias for the standard MemoryError, these exceptions are\n"\
+"derived from a common pygetdata.DirfileError exception class, itself\n"\
+"derived from RuntimeError.  Exceptions are thrown by the bindings in\n"\
+"lieu of returning a dirfile error value.\n" \
+"\n" \
+"Where possible, pygetdata will, by default, return vector data as NumPy\n" \
+"arrays.  If pygetdata has been built with NumPy support,\n" \
+"pygetdata.__numpy_supported__ will be non-zero.  If NumPy support is not\n" \
+"npresent, vector data will be returned as Python lists.  Vector data\n" \
+"passed to pygetdata may either be a Python list or a NumPy array.\n" \
+"\n" \
+"The input data type argument to bindings for functions such as\n" \
+"gd_putdata(3), which is required in the C API, are typically optional,\n" \
+"as pygetdata can determine the input data type by itself, and convert it\n" \
+"to an appropriate type for the C API.  If the data type is supplied,\n" \
+"pygetdata will coerce the input data to the specified C type as best it\n" \
+"can.  For gd_getdata(3) and similar, the C API types are converted to\n" \
+"Python types as follows:\n\n" \
+"  o int     -- UINT8, INT8, UINT16, INT16, INT32\n" \
+"  o long    -- UINT32, UINT64, INT64\n" \
+"  o float   -- FLOAT32, FLOAT64\n" \
+"  o complex -- COMPLEX64, COMPLEX128\n\n" \
+"or to NumPy data types, as appropriate.  For convenience, the following\n" \
+"type code aliases are defined:\n" \
+"\n" \
+"  o pygetdata.INT     = pygetdata.INT32\n" \
+"  o pygetdata.LONG    = pygetdata.INT64\n" \
+"  o pygetdata.ULONG   = pygetdata.UINT64\n" \
+"  o pygetdata.FLOAT   = pygetdata.FLOAT64\n" \
+"  o pygetdata.COMPLEX = pygetdata.COMPLEX128\n\n" \
+"Note that pygetdata.FLOAT is different than the C API's GD_FLOAT alias.\n" \
+"\n" \
+"All pygetdata functions may be given positional or keyword parameters.\n" \
+"\n" \
+"CHARACTER STRINGS AND ENCODINGS:\n" \
+"\n" \
+"The Dirfile Standards do not specify the character encoding scheme used\n" \
+"in the Dirfile metadata (other than requiring it to be 7-bit ASCII\n" \
+"compatible).  As a result, pygetdata does not by default decode most\n" \
+"strings provided by the library, instead returning them as encoded" \
+GDPY_MODULE_DOC23("bytes\nobjects.\n\n", "\nstrings.\n\n") \
+"This behaviour may be changed by specifying the character encoding to use\n" \
+"for decoding strings, either globally, by assigning to the\n" \
+"pygetdata.character_encoding, or else per-object by assigning to a \n"\
+"pygetdata.dirfile or pygetdata.entry object's character_encoding attribute.\n"\
+"(pygetdata.fragment objects use the character_encoding of their containing\n"\
+"dirfile.)  The value assigned should either be None, indicating no decoding\n"\
+"should occur (this is the default), or else a string giving the name of the\n"\
+"character encoding to use.  This should be one of the encodings supported\n"\
+"by the " \
+GDPY_MODULE_DOC23("unicode()","str()") \
+"built-in." \
+"\n"\
+"The global pygetdata.character_encoding is never used directly, but is\n" \
+"copied when new pygetdata objects are created.  If the global value is\n" \
+"not valid when an object is created, it is ignored and that object's\n" \
+"character encoding attribute is simply set to None.\n" \
+"\n" \
+"This also determines how Unicode strings passed to pygetdata are encoding\n" \
+"before being passed to the C library.  If character_encoding is None, the\n" \
+"current locale's default encoding is used instead.\n" \
+"\n"\
+"String conversion occurs on demand: changing an object's character_encoding\n"\
+"attribute affects all strings subsequently passed to or returned by the\n" \
+"object.  Changing the global pygetdata.character_encoding only affects\n" \
+"object created after the change: it does not alter the character_encoding\n" \
+"attribute of pre-existing objects, even if the attribute is None.\n"
+
+GDPY_MODINITFUNC
 {
   int i;
-  PyObject *mod;
-  PyObject *mdict;
+  PyObject *mdict, *dirfileerror;
+#if PY_MAJOR_VERSION >= 3
+  static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "pygetdata",     /* m_name */
+    GDPY_MODULE_DOC, /* m_doc */
+    -1,              /* m_size */
+    GetDataMethods,  /* m_methods */
+    NULL,            /* m_reload */
+    NULL,            /* m_traverse */
+    NULL,            /* m_clear */
+    NULL             /* m_free */
+  };
+#endif
 
-  dtracevoid();
+#ifdef PYGETDATA_CAPI
+  PyObject *capi;
+  static void *gdpy_api[PyDirfile_API_length];
+#endif
 
   if (PyType_Ready(&gdpy_dirfile) < 0)
-    return;
+    GDPY_MODINITFAILURE;
 
   if (PyType_Ready(&gdpy_entry) < 0)
-    return;
+    GDPY_MODINITFAILURE;
 
   if (PyType_Ready(&gdpy_fragment) < 0)
-    return;
+    GDPY_MODINITFAILURE;
 
   /* The following macro will cause this function to return if importing numpy
    * fails */
   import_array()
 
-  mod = Py_InitModule3("pygetdata", GetDataMethods,
-      "Bindings to the GetData library for Dirfile access\n\n"
-      "This module provides interfaces to the C GetData library.  It defines "
-      "three\nmain classes:\n\n"
-      "  o dirfile, encapsulating the C API's DIRFILE object,\n"
-      "  o entry, encapsulating the C API's gd_entry_t object, and\n"
-      "  o fragment, containing fragment metadata.\n\n"
-      "Second, it defines various symbolic constants defined by the C API.  "
-      "These\nsymbols are identical to the C API's symbols, except lacking the "
-      "GD_ prefix.\nSo, for example, the C API's GD_INT8 is available in these "
-      "bindings as\npygetdata.INT8.\n\n"
-      "Finally, it defines a number of exceptions corresponding to C API "
-      "dirfile\nerror codes.  These exceptions have similar names to the C "
-      "API's error\nnames, so, for example, pygetdata.BadCodeError corresponds "
-      "to the C API's\nGD_E_BAD_CODE error code.  All these exceptions are "
-      "derived from a common\npygetdata.DirfileError exception class, itself "
-      "derived from RuntimeError.\nExceptions are thrown by the bindings in "
-      "lieu of returning a dirfile error\nvalue.\n\n"
-      "Where possible, pygetdata will, by default, return vector data as "
-      "NumPy\narrays.  If "
-      "pygetdata has been built with NumPy support,\n"
-      "pygetdata.__numpy_supported__ will be non-zero.  If NumPy support is "
-      "not\npresent, vector data will be returned as Python lists.  Vector "
-      "data passed\nto pygetdata may either be a Python list or a NumPy array."
-      "\n\n"
-      "The input data type argument to bindings for functions such as\n"
-      "gd_putdata(3), which is required in the C API, are typically optional,\n"
-      "as pygetdata can determine the input data type by itself, and convert "
-      "it to\nan appropriate type for the C API.  If the data type is supplied,"
-      " pygetdata\nwill coerce the input data to the specified C type as best "
-      "it can.  For\ngd_getdata(3) and similar, the C API types are converted "
-      "to Python types as\nfollows:\n\n"
-      "  o int     -- UINT8, INT8, UINT16, INT16, INT32\n"
-      "  o long    -- UINT32, UINT64, INT64\n"
-      "  o float   -- FLOAT32, FLOAT64\n"
-      "  o complex -- COMPLEX64, COMPLEX128\n\n"
-      "or to NumPy data types, as appropriate.  "
-      "For convenience, the following type\ncode aliases are defined:\n\n"
-      "  o pygetdata.INT     = pygetdata.INT32\n"
-      "  o pygetdata.LONG    = pygetdata.INT64\n"
-      "  o pygetdata.ULONG   = pygetdata.UINT64\n"
-      "  o pygetdata.FLOAT   = pygetdata.FLOAT64\n"
-      "  o pygetdata.COMPLEX = pygetdata.COMPLEX128\n\n"
-      "Note that pygetdata.FLOAT is different than the C API's GD_FLOAT "
-      "alias.\n\n"
-      "All pygetdata functions may be given positional or keyword parameters."
-      );
-
-  if (mod == NULL)
-    return;
+#if PY_MAJOR_VERSION < 3
+  gdpy_mod = Py_InitModule3("pygetdata", GetDataMethods, GDPY_MODULE_DOC);
+#else
+  gdpy_mod = PyModule_Create(&moduledef);
+#endif
+
+  if (gdpy_mod == NULL)
+    GDPY_MODINITFAILURE;
 
   Py_INCREF(&gdpy_dirfile);
-  PyModule_AddObject(mod, "dirfile", (PyObject *)&gdpy_dirfile);
+  PyModule_AddObject(gdpy_mod, "dirfile", (PyObject *)&gdpy_dirfile);
 
   Py_INCREF(&gdpy_entry);
-  PyModule_AddObject(mod, "entry", (PyObject *)&gdpy_entry);
+  PyModule_AddObject(gdpy_mod, "entry", (PyObject *)&gdpy_entry);
 
   Py_INCREF(&gdpy_fragment);
-  PyModule_AddObject(mod, "fragment", (PyObject *)&gdpy_fragment);
+  PyModule_AddObject(gdpy_mod, "fragment", (PyObject *)&gdpy_fragment);
 
   /* version */
-  PyModule_AddObject(mod, "__version__", Py_BuildValue("(iiis)", GETDATA_MAJOR,
-        GETDATA_MINOR, GETDATA_REVISION, GETDATA_VERSION_SUFFIX));
+  PyModule_AddObject(gdpy_mod, "__version__", Py_BuildValue("(iiis)",
+        GETDATA_MAJOR, GETDATA_MINOR, GETDATA_REVISION,
+        GETDATA_VERSION_SUFFIX));
 
   /* author */
-  PyModule_AddStringConstant(mod, "__author__",
+  PyModule_AddStringConstant(gdpy_mod, "__author__",
       "The GetData Project <http://getdata.sourceforge.net/>");
 
+  /* character_encoding */
+  Py_INCREF(Py_None);
+  PyModule_AddObject(gdpy_mod, "character_encoding", Py_None);
+
   /* add constants */
   for (i = 0; gdpy_constant_list[i].name != NULL; ++i)
-    PyModule_AddIntConstant(mod, gdpy_constant_list[i].name,
+    PyModule_AddIntConstant(gdpy_mod, gdpy_constant_list[i].name,
         gdpy_constant_list[i].value);
 
-  PyModule_AddIntConstant(mod, "__numpy_supported__", 1);
+  PyModule_AddIntConstant(gdpy_mod, "__numpy_supported__", 1);
 
   /* add exceptions */
-  GdPy_DirfileError = PyErr_NewException("pygetdata.DirfileError",
+  dirfileerror = PyErr_NewExceptionWithDoc("pygetdata.DirfileError",
+      "The base exception for all Dirfile-specific exceptions.",
       PyExc_RuntimeError, NULL);
-  Py_INCREF(GdPy_DirfileError);
-  PyModule_AddObject(mod, "DirfileError", GdPy_DirfileError);
+  Py_INCREF(dirfileerror);
+  PyModule_AddObject(gdpy_mod, "DirfileError", dirfileerror);
 
   for (i = 1; i < GD_N_ERROR_CODES; ++i) {
-    if (gdpy_exception_list[i]) {
+    if (gdpy_exception_list[i].name) {
       char name[40];
-      sprintf(name, "pygetdata.%sError", gdpy_exception_list[i]);
-      gdpy_exceptions[i] = PyErr_NewException(name, GdPy_DirfileError, NULL);
+      sprintf(name, "pygetdata.%sError", gdpy_exception_list[i].name);
+      gdpy_exceptions[i] = PyErr_NewExceptionWithDoc(name,
+          gdpy_exception_list[i].doc, dirfileerror, NULL);
       Py_INCREF(gdpy_exceptions[i]);
-      PyModule_AddObject(mod, name + 10, gdpy_exceptions[i]);
+      PyModule_AddObject(gdpy_mod, name + 10, gdpy_exceptions[i]);
     } else
-      gdpy_exceptions[i] = GdPy_DirfileError;
+      gdpy_exceptions[i] = dirfileerror;
   }
 
   /* add dead exceptions -- we do this through manual dictionary editing */
-  mdict = PyModule_GetDict(mod);
+  mdict = PyModule_GetDict(gdpy_mod);
   if (mdict)
     for (i = 0; gdpy_dead_exceptions[i].name; ++i) {
       char name[40];
@@ -721,5 +1127,23 @@ PyMODINIT_FUNC initpygetdata(void)
           gdpy_exceptions[gdpy_dead_exceptions[i].e]);
     }
 
-  dreturnvoid();
+  /* Also add an alias for AllocError */
+  if (mdict) {
+    Py_INCREF(PyExc_MemoryError);
+    PyDict_SetItemString(mdict, "AllocError", PyExc_MemoryError);
+  }
+
+  /* Create the CAPI Capsule, if we can */
+#ifdef PYGETDATA_CAPI
+  gdpy_api[PyDirfile_Type_NUM] = &gdpy_dirfile;
+  gdpy_api[PyDirfile_Dirfile_NUM] = &gdpy_dirfile_dirfile;
+  gdpy_api[PyDirfile_Raise_NUM] = &gdpy_dirfile_raise;
+
+  capi = PyCapsule_New(gdpy_api, PYDIRFILE_CAPSULENAME, NULL);
+  
+  if (capi)
+    PyModule_AddObject(gdpy_mod, "__CAPI", capi);
+#endif
+
+  GDPY_MODINITSUCCESS;
 }
diff --git a/bindings/python/pygetdata.h b/bindings/python/pygetdata.h
index d3d66ac..084bb63 100644
--- a/bindings/python/pygetdata.h
+++ b/bindings/python/pygetdata.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2015 D. V. Wiebe
+/* Copyright (C) 2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -18,128 +18,47 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include <Python.h>
 
-#undef _BSD_SOURCE
-#undef _POSIX_SOURCE
-#undef _SVID_SOURCE
-#undef _POSIX_C_SOURCE
-#undef SIZEOF_OFF_T
-#include "../../src/internal.h"
+/* This header file defines the pygetdata C API */
+#ifndef CPYGETDATA_H
+#define CPYGETDATA_H
 
-#ifdef HAVE_NUMPY_ARRAYOBJECT_H
-# define PY_ARRAY_UNIQUE_SYMBOL gdpy_array_api
-# include <numpy/arrayobject.h>
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-#define GDPY_UNSIGNED        0x00
-#define GDPY_SIGNED          0x01
-#define GDPY_IEEE754         0x02
-#define GDPY_COMPLEX         0x03
+#include <getdata.h>
 
-#define GDPY_INT             0x00
-#define GDPY_LONG            0x10
-#define GDPY_FLOAT           0x20
-#define GDPY_PYCOMPLEX       0x40
+#define PyDirfile_Type_NUM 0
+#define PyDirfile_Dirfile_NUM 1
+#define PyDirfile_Raise_NUM 2
 
-#define GDPY_INT_AS_LONG        (GDPY_INT       | GDPY_SIGNED)
-#define GDPY_LONG_AS_ULL        (GDPY_LONG      | GDPY_UNSIGNED)
-#define GDPY_LONG_AS_SLL        (GDPY_LONG      | GDPY_SIGNED)
-#define GDPY_LONG_AS_DOUBLE     (GDPY_LONG      | GDPY_IEEE754)
-#define GDPY_FLOAT_AS_DOUBLE    (GDPY_FLOAT     | GDPY_IEEE754)
-#define GDPY_COMPLEX_AS_COMPLEX (GDPY_PYCOMPLEX | GDPY_COMPLEX)
+#define PyDirfile_API_length 3
 
-#define GDPY_INVALID_OP(t) ( \
-    t != GD_WINDOP_EQ && t != GD_WINDOP_NE && \
-    t != GD_WINDOP_GE && t != GD_WINDOP_GT && \
-    t != GD_WINDOP_LE && t != GD_WINDOP_LT && \
-    t != GD_WINDOP_SET && t != GD_WINDOP_CLR )
+#define PYDIRFILE_CAPSULENAME "pygetdata.__CAPI"
 
-#define GDPY_INVALID_TYPE(t) ( \
-    t != GD_UINT8     && t != GD_INT8    && \
-    t != GD_UINT16    && t != GD_INT16   && \
-    t != GD_UINT32    && t != GD_INT32   && \
-    t != GD_UINT64    && t != GD_INT64   && \
-    t != GD_FLOAT32   && t != GD_FLOAT64 && \
-    t != GD_COMPLEX64 && t != GD_COMPLEX128 )
+#ifndef PYGETDATA_MODULE
 
-#define PYGD_CHECK_ERROR(D,R) PYGD_CHECK_ERROR2(D,R,)
+  static void **PyDirfile_API;
 
-#define PYGD_CHECK_ERROR2(D,R,E) \
-  do { \
-    int e; \
-    if ((e = gd_error(D))) { \
-      PYGD_REPORT_ERROR(D,e); \
-      E; \
-      dreturnvoid(); \
-      return (R); \
-    } \
-  } while(0)
+#define PyDirfile_Type (*(PyTypeObject*)PyDirfile_API[PyDirfile_Type_NUM])
+#define PyDirfile_Dirfile \
+  (*(DIRFILE *(*)(PyObject*))PyDirfile_API[PyDirfile_Dirfile_NUM])
+#define PyDirfile_Raise \
+  (*(int (*)(PyObject*))PyDirfile_API[PyDirfile_Raise_NUM])
 
-#define PYGD_REPORT_ERROR(D,e) \
-  do { \
-    char *buffer = gd_error_string((D), NULL, 0); \
-    if (buffer) { \
-      PyErr_SetString(gdpy_exceptions[e], buffer); \
-      free(buffer); \
-    } else \
-      PyErr_SetString(gdpy_exceptions[e], "Unspecified error"); \
-  } while (0)
+#define PyDirfile_Check(o) PyObject_TypeCheck(o, &PyDirfile_Type)
 
+  static int import_pygetdata(void)
+  {
+    PyDirfile_API = (void**)PyCapsule_Import(PYDIRFILE_CAPSULENAME, 0);
+    return (PyDirfile_API == NULL) ? 1 : 0;
+  }
 
-extern PyObject *gdpy_exceptions[GD_N_ERROR_CODES];
-extern PyTypeObject gdpy_dirfile;
-extern PyTypeObject gdpy_entry;
-extern PyTypeObject gdpy_fragment;
-
-extern const struct gdpy_constant_t {
-  char *name;
-  long value;
-} gdpy_constant_list[];
-
-struct gdpy_dirfile_t {
-  PyObject_HEAD
-  DIRFILE *D;
-  int mplex_lookback;
-  char *verbose_prefix;
-  PyObject *callback_data;
-  PyObject *callback;
-  int callback_exception;
-};
-
-struct gdpy_entry_t {
-  PyObject_HEAD
-  gd_entry_t *E;
-};
-
-struct gdpy_fragment_t {
-  PyObject_HEAD
-  int n;
-  struct gdpy_dirfile_t *dirfile;
-};
-
-union gdpy_quadruple_value {
-  uint64_t u;
-  int64_t s;
-  double f;
-  GD_DCOMPLEXA(c);
-};
-
-#define gdpy_as_complex(v,o) do { \
-  Py_complex c = PyComplex_AsCComplex(o); \
-  gd_li2cp_((v), c.real, c.imag); \
-} while(0)
+#endif
 
-#define gdpy_from_complexp(c) PyComplex_FromDoubles((c)[0], (c)[1])
-#define gdpy_from_complex(c) PyComplex_FromDoubles(creal(c), cimag(c))
+#ifdef __cplusplus
+}
+#endif
 
-extern int gdpylist_append(PyObject *, PyObject *);
-extern int gdpy_convert_from_pyobj(PyObject*, union gdpy_quadruple_value*,
-    gd_type_t);
-extern gd_type_t gdpy_convert_from_pylist(PyObject*, void*, gd_type_t, size_t);
-extern PyObject *gdpy_convert_to_pyobj(const void*, gd_type_t);
-extern PyObject *gdpy_convert_to_pylist(const void*, gd_type_t, size_t);
-extern PyObject *gdpy_to_pystringlist(const char **list);
-extern int gdpy_npytype_from_type(gd_type_t type);
-extern gd_type_t gdpy_type_from_npytype(int npytype);
-PyMODINIT_FUNC initpygetdata(void);
+#endif
diff --git a/bindings/python/test/Makefile.am b/bindings/python/test/Makefile.am
index 32d786f..917c603 100644
--- a/bindings/python/test/Makefile.am
+++ b/bindings/python/test/Makefile.am
@@ -22,7 +22,7 @@ AUTOMAKE_OPTIONS = foreign serial-tests
 
 if TEST_PYTHON
 TESTS_ENVIRONMENT=${DL_LIBRARY_PATH}=../../../src/.libs:${${DL_LIBRARY_PATH}} PYTHONPATH=..:${PYTHONPATH} ${PYTHON}
-pyTESTS=callback.py big_test.py
+pyTESTS=callback.py char_enc1.py char_enc2.py char_enc3.py big_test.py
 TESTS=$(addprefix ${srcdir}/,$(pyTESTS))
 endif
 
diff --git a/bindings/python/test/Makefile.in b/bindings/python/test/Makefile.in
index 2fb5b1a..25dfe9d 100644
--- a/bindings/python/test/Makefile.in
+++ b/bindings/python/test/Makefile.in
@@ -286,6 +286,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -335,6 +336,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -398,7 +400,7 @@ top_srcdir = @top_srcdir@
 #
 AUTOMAKE_OPTIONS = foreign serial-tests
 @TEST_PYTHON_TRUE at TESTS_ENVIRONMENT = ${DL_LIBRARY_PATH}=../../../src/.libs:${${DL_LIBRARY_PATH}} PYTHONPATH=..:${PYTHONPATH} ${PYTHON}
- at TEST_PYTHON_TRUE@pyTESTS = callback.py big_test.py
+ at TEST_PYTHON_TRUE@pyTESTS = callback.py char_enc1.py char_enc2.py char_enc3.py big_test.py
 @TEST_PYTHON_TRUE at TESTS = $(addprefix ${srcdir}/,$(pyTESTS))
 EXTRA_DIST = ${pyTESTS}
 all: all-am
diff --git a/bindings/python/test/big_test.py b/bindings/python/test/big_test.py
index 034db02..eb21c41 100644
--- a/bindings/python/test/big_test.py
+++ b/bindings/python/test/big_test.py
@@ -25,71 +25,85 @@ import array
 import pygetdata
 import numpy
 
+# These two functions abstractify differences between Python2 and 3.
+def L(n):
+  if sys.version[:1] == '3':
+    return n
+  return long(n)
+
+def B(s):
+  if sys.version[:1] == '3':
+    return bytes(s, "ASCII")
+  return s
+
+
+
+
 def CheckOK(t):
   global ne
   ne+=1
-  print "e[", t, "] =", sys.exc_type, sys.exc_value
+  print ("e[", t, "] =", sys.exc_info()[0], sys.exc_value)
 
 def CheckOK2(t,m):
   global ne
   ne+=1
-  print "e[", t, ",", m, "] =", sys.exc_type, sys.exc_value
+  print ("e[", t, ",", m, "] =", sys.exc_info()[0], sys.exc_value)
 
 def CheckException(t,g):
   global ne
-  if (sys.exc_type != g):
+  if (sys.exc_info()[0] != g):
     ne+=1
-    print "e[", t, "] =", sys.exc_type, "expected", g
+    print ("e[", t, "] =", sys.exc_info()[0], "expected", g)
 
 def CheckException2(t,m,g):
   global ne
-  if (sys.exc_type != g):
+  if (sys.exc_info()[0] != g):
     ne+=1
-    print "e[", t, ",", m, "] =", sys.exc_type, "expected", g
+    print ("e[", t, ",", m, "] =", sys.exc_info()[0], "expected", g)
 
 def CheckNumpy(t,v,g):
   global ne
   if (numpy.any(v - g)):
     ne+=1
-    print "a[", t, "] =", v, "expected", g
+    print ("a[", t, "] =", v, "expected", g)
 
 def CheckNumpy2(t,m,v,g):
   global ne
   if (numpy.any(v - g)):
     ne+=1
-    print "a[", t, ",", m, "] =", v, "expected", g
+    print ("a[", t, ",", m, "] =", v, "expected", g)
 
 def CheckSimple(t,v,g):
   global ne
   if (v != g):
     ne+=1
-    print "n[", t, "] =", v, "expected", g
+    print ("n[", t, "] =", v, "expected", g)
 
 def CheckSimple2(t,m,v,g):
   global ne
   if (v != g):
     ne+=1
-    print "n[", t, ",", m, "] =", v, "expected", g
+    print ("n[", t, ",", m, "] =", v, "expected", g)
 
 def CheckEOS(t,v,g):
   global ne
   if (re.search(g + "$", v) == None):
     ne+=1
-    print "n[", t, "] =", v, "expected", g
+    print ("n[", t, "] =", v, "expected", g)
 
 # create the dirfile first
 data=array.array("B",range(1,81))
 os.system("rm -rf dirfile")
 os.mkdir("dirfile")
-file=open("dirfile/data", 'w')
+file=open("dirfile/data", 'wb')
 data.tofile(file)
 file.close()
 
 ne = 0
 
-fields = ["INDEX", "alias", "bit", "carray", "const", "data", "div", "lincom",
-"linterp", "mplex", "mult", "phase", "polynom", "recip", "sbit", "string",
-"window"]
+fields = [B("INDEX"), B("alias"), B("bit"), B("carray"), B("const"), B("data"),
+    B("div"), B("lincom"), B("linterp"), B("mplex"), B("mult"), B("phase"),
+    B("polynom"), B("recip"), B("sbit"), B("string"), B("window")]
 
 nfields = 17
 file=open("dirfile/format", 'w')
@@ -148,7 +162,7 @@ try:
 except:
   CheckOK(6)
 CheckSimple(6,len(n),8)
-CheckNumpy(6,n,numpy.arange(41L,49L))
+CheckNumpy(6,n,numpy.arange(L(41),L(49)))
 
 # 8: getdata (float) check
 try:
@@ -171,7 +185,7 @@ try:
   n = d.getdata("data", pygetdata.NULL, first_frame=5, num_frames=1)
 except:
   CheckOK(11)
-CheckSimple(11, n, 8);
+CheckSimple(11, n, 8)
 
 # 12: constant (int) check
 try:
@@ -185,7 +199,7 @@ try:
   n = d.get_constant("const", pygetdata.LONG)
 except:
   CheckOK(15)
-CheckSimple(15,n,5L)
+CheckSimple(15,n,L(5))
 
 # 16: constant (float) check
 try:
@@ -241,7 +255,7 @@ try:
   n = d.mfield_list("data")
 except:
   CheckOK(27)
-CheckSimple(27,n,["mstr", "mconst", "mcarray", "mlut"])
+CheckSimple(27,n,[B("mstr"), B("mconst"), B("mcarray"), B("mlut")])
 
 # 28: nframes check
 try:
@@ -286,7 +300,7 @@ except:
 CheckNumpy2(32,2,n,numpy.array([41, 73, 74, 75, 76, 46, 47, 48]))
 
 # 33: putdata (long) check
-p = [ 23L, 24L, 25L, 26L ]
+p = [ L(23), L(24), L(25), L(26) ]
 try:
   n = d.putdata("data", p, pygetdata.LONG, first_frame=5, first_sample=1)
 except:
@@ -355,9 +369,9 @@ CheckSimple2(42,1,ent.field_type,pygetdata.LINCOM_ENTRY)
 CheckSimple2(42,2,ent.field_type_name,"LINCOM_ENTRY")
 CheckSimple2(42,3,ent.fragment,0)
 CheckSimple2(42,4,ent.n_fields,3)
-CheckSimple2(42,5,ent.in_fields,( "data", "INDEX", "linterp" ))
-CheckSimple2(42,6,ent.m,(1.1, 2.2, "const"))
-CheckSimple2(42,7,ent.b,(2.2, 3.3 + 4.4j, "const"))
+CheckSimple2(42,5,ent.in_fields,(B("data"), B("INDEX"), B("linterp")))
+CheckSimple2(42,6,ent.m,(1.1, 2.2, B("const")))
+CheckSimple2(42,7,ent.b,(2.2, 3.3 + 4.4j, B("const")))
 
 # 44: entry (polynom) check
 try:
@@ -368,8 +382,8 @@ CheckSimple2(44,1,ent.field_type,pygetdata.POLYNOM_ENTRY)
 CheckSimple2(44,2,ent.field_type_name,"POLYNOM_ENTRY")
 CheckSimple2(44,3,ent.fragment,0)
 CheckSimple2(44,4,ent.poly_ord,5)
-CheckSimple2(44,5,ent.in_fields,( "data", ))
-CheckSimple2(44,6,ent.a,(1.1, 2.2, 2.2, 3.3 + 4.4j, "const", "const"))
+CheckSimple2(44,5,ent.in_fields,( B("data"), ))
+CheckSimple2(44,6,ent.a,(1.1, 2.2, 2.2, 3.3 + 4.4j, B("const"), B("const")))
 
 # 45: entry (linterp) check
 try:
@@ -379,7 +393,7 @@ except:
 CheckSimple2(45,1,ent.field_type,pygetdata.LINTERP_ENTRY)
 CheckSimple2(45,2,ent.field_type_name,"LINTERP_ENTRY")
 CheckSimple2(45,3,ent.fragment,0)
-CheckSimple2(45,4,ent.in_fields,( "data", ))
+CheckSimple2(45,4,ent.in_fields,( B("data"), ))
 CheckSimple2(45,5,ent.table,"./lut")
 
 # 46: entry (bit) check
@@ -390,7 +404,7 @@ except:
 CheckSimple2(46,1,ent.field_type,pygetdata.BIT_ENTRY)
 CheckSimple2(46,2,ent.field_type_name,"BIT_ENTRY")
 CheckSimple2(46,3,ent.fragment,0)
-CheckSimple2(46,4,ent.in_fields,( "data", ))
+CheckSimple2(46,4,ent.in_fields,( B("data"), ))
 CheckSimple2(46,5,ent.numbits,4)
 CheckSimple2(46,6,ent.bitnum,3)
 
@@ -402,7 +416,7 @@ except:
 CheckSimple2(47,1,ent.field_type,pygetdata.SBIT_ENTRY)
 CheckSimple2(47,2,ent.field_type_name,"SBIT_ENTRY")
 CheckSimple2(47,3,ent.fragment,0)
-CheckSimple2(47,4,ent.in_fields,( "data", ))
+CheckSimple2(47,4,ent.in_fields,( B("data"), ))
 CheckSimple2(47,5,ent.numbits,6)
 CheckSimple2(47,6,ent.bitnum,5)
 
@@ -414,7 +428,7 @@ except:
 CheckSimple2(48,1,ent.field_type,pygetdata.MULTIPLY_ENTRY)
 CheckSimple2(48,2,ent.field_type_name,"MULTIPLY_ENTRY")
 CheckSimple2(48,3,ent.fragment,0)
-CheckSimple2(48,4,ent.in_fields,( "data", "sbit"))
+CheckSimple2(48,4,ent.in_fields,( B("data"), B("sbit")))
 
 # 49: entry (phase) check
 try:
@@ -424,7 +438,7 @@ except:
 CheckSimple2(49,1,ent.field_type,pygetdata.PHASE_ENTRY)
 CheckSimple2(49,2,ent.field_type_name,"PHASE_ENTRY")
 CheckSimple2(49,3,ent.fragment,0)
-CheckSimple2(49,4,ent.in_fields,( "data", ))
+CheckSimple2(49,4,ent.in_fields,( B("data"), ))
 CheckSimple2(49,5,ent.shift,11)
 
 # 50: entry (const) check
@@ -488,13 +502,13 @@ CheckSimple2(54,1,ent.field_type,pygetdata.LINCOM_ENTRY)
 CheckSimple2(54,2,ent.field_type_name,"LINCOM_ENTRY")
 CheckSimple2(54,3,ent.fragment,0)
 CheckSimple2(54,4,ent.n_fields,2)
-CheckSimple2(54,5,ent.in_fields,( "in1", "in2" ))
+CheckSimple2(54,5,ent.in_fields,( B("in1"), B("in2") ))
 CheckSimple2(54,6,ent.m,(9.9, 7.7))
 CheckSimple2(54,7,ent.b,(8.8, 6.6))
 
 # 56: add / entry (polynom) check
 ent = pygetdata.entry(pygetdata.POLYNOM_ENTRY, "new4", 0,
-    ("in1", (3.9, 4.8, 5.7, 6.6)))
+    (B("in1"), (3.9, 4.8, 5.7, 6.6)))
 try:
   d.add(ent)
 except:
@@ -508,12 +522,12 @@ CheckSimple2(56,1,ent.field_type,pygetdata.POLYNOM_ENTRY)
 CheckSimple2(56,2,ent.field_type_name,"POLYNOM_ENTRY")
 CheckSimple2(56,3,ent.fragment,0)
 CheckSimple2(56,4,ent.poly_ord,3)
-CheckSimple2(56,5,ent.in_fields,( "in1", ))
+CheckSimple2(56,5,ent.in_fields,( B("in1"), ))
 CheckSimple2(56,6,ent.a,(3.9, 4.8, 5.7, 6.6))
 
 # 58: add / entry (linterp) check
 ent = pygetdata.entry(pygetdata.LINTERP_ENTRY, "new6", 0,
-    ("in", "./some/table"))
+    (B("in"), "./some/table"))
 try:
   d.add(ent)
 except:
@@ -526,7 +540,7 @@ except:
 CheckSimple2(58,1,ent.field_type,pygetdata.LINTERP_ENTRY)
 CheckSimple2(58,2,ent.field_type_name,"LINTERP_ENTRY")
 CheckSimple2(58,3,ent.fragment,0)
-CheckSimple2(58,4,ent.in_fields,( "in", ))
+CheckSimple2(58,4,ent.in_fields,( B("in"), ))
 CheckSimple2(58,5,ent.table,"./some/table")
 
 # 59: add / entry (bit) check
@@ -543,7 +557,7 @@ except:
 CheckSimple2(59,1,ent.field_type,pygetdata.BIT_ENTRY)
 CheckSimple2(59,2,ent.field_type_name,"BIT_ENTRY")
 CheckSimple2(59,3,ent.fragment,0)
-CheckSimple2(59,4,ent.in_fields,( "in", ))
+CheckSimple2(59,4,ent.in_fields,( B("in"), ))
 CheckSimple2(59,5,ent.numbits,12)
 CheckSimple2(59,6,ent.bitnum,13)
 
@@ -561,7 +575,7 @@ except:
 CheckSimple2(60,1,ent.field_type,pygetdata.SBIT_ENTRY)
 CheckSimple2(60,2,ent.field_type_name,"SBIT_ENTRY")
 CheckSimple2(60,3,ent.fragment,0)
-CheckSimple2(60,4,ent.in_fields,( "in2", ))
+CheckSimple2(60,4,ent.in_fields,( B("in2"), ))
 CheckSimple2(60,5,ent.bitnum,14)
 CheckSimple2(60,6,ent.numbits,15)
 
@@ -579,7 +593,7 @@ except:
 CheckSimple2(61,1,ent.field_type,pygetdata.MULTIPLY_ENTRY)
 CheckSimple2(61,2,ent.field_type_name,"MULTIPLY_ENTRY")
 CheckSimple2(61,3,ent.fragment,0)
-CheckSimple2(61,4,ent.in_fields,( "in1", "in2"))
+CheckSimple2(61,4,ent.in_fields,( B("in1"), B("in2")))
 
 # 62: add / entry (phase) check
 ent = pygetdata.entry(pygetdata.PHASE_ENTRY, "new10", 0, ("in1", 22))
@@ -595,7 +609,7 @@ except:
 CheckSimple2(62,1,ent.field_type,pygetdata.PHASE_ENTRY)
 CheckSimple2(62,2,ent.field_type_name,"PHASE_ENTRY")
 CheckSimple2(62,3,ent.fragment,0)
-CheckSimple2(62,4,ent.in_fields,( "in1", ))
+CheckSimple2(62,4,ent.in_fields,( B("in1"), ))
 CheckSimple2(62,5,ent.shift,22)
 
 # 63: add / entry (const) check
@@ -654,7 +668,7 @@ try:
   n = d.field_list(pygetdata.LINCOM_ENTRY)
 except:
   CheckOK(68)
-CheckSimple(68,n,["lincom", "new2"])
+CheckSimple(68,n,[B("lincom"), B("new2")])
 
 # 69: nvectors check
 try:
@@ -668,9 +682,10 @@ try:
   n = d.vector_list()
 except:
   CheckOK(70)
-CheckSimple(70,n,['INDEX', 'alias', 'bit', 'data', 'div', 'lincom', 'linterp',
-  'mplex', 'mult', 'new1', 'new10', 'new2', 'new4', 'new6', 'new7', 'new8',
-  'new9', 'phase', 'polynom', 'recip', 'sbit', 'window'])
+CheckSimple(70,n,[B('INDEX'), B('alias'), B('bit'), B('data'), B('div'),
+    B('lincom'), B('linterp'), B('mplex'), B('mult'), B('new1'), B('new10'),
+    B('new2'), B('new4'), B('new6'), B('new7'), B('new8'), B('new9'),
+    B('phase'), B('polynom'), B('recip'), B('sbit'), B('window')])
 
 # 71: add / entry (lincom) check
 ent = pygetdata.entry(pygetdata.LINCOM_ENTRY, "mnew1", 0,
@@ -688,7 +703,7 @@ CheckSimple2(71,1,ent.field_type,pygetdata.LINCOM_ENTRY)
 CheckSimple2(71,2,ent.field_type_name,"LINCOM_ENTRY")
 CheckSimple2(71,3,ent.fragment,0)
 CheckSimple2(71,4,ent.n_fields,2)
-CheckSimple2(71,5,ent.in_fields,( "in1", "in2" ))
+CheckSimple2(71,5,ent.in_fields,( B("in1"), B("in2") ))
 CheckSimple2(71,6,ent.m,(9.9, 7.7))
 CheckSimple2(71,7,ent.b,(8.8, 6.6))
 
@@ -708,7 +723,7 @@ CheckSimple2(73,1,ent.field_type,pygetdata.POLYNOM_ENTRY)
 CheckSimple2(73,2,ent.field_type_name,"POLYNOM_ENTRY")
 CheckSimple2(73,3,ent.fragment,0)
 CheckSimple2(73,4,ent.poly_ord,3)
-CheckSimple2(73,5,ent.in_fields,( "in1", ))
+CheckSimple2(73,5,ent.in_fields,( B("in1"), ))
 CheckSimple2(73,6,ent.a,(3.9, 4.8, 5.7, 6.6))
 
 # 75: add / entry (linterp) check
@@ -726,7 +741,7 @@ except:
 CheckSimple2(75,1,ent.field_type,pygetdata.LINTERP_ENTRY)
 CheckSimple2(75,2,ent.field_type_name,"LINTERP_ENTRY")
 CheckSimple2(75,3,ent.fragment,0)
-CheckSimple2(75,4,ent.in_fields,( "in", ))
+CheckSimple2(75,4,ent.in_fields,( B("in"), ))
 CheckSimple2(75,5,ent.table,"./more/table")
 
 # 76: add / entry (bit) check
@@ -744,7 +759,7 @@ except:
 CheckSimple2(76,1,ent.field_type,pygetdata.BIT_ENTRY)
 CheckSimple2(76,2,ent.field_type_name,"BIT_ENTRY")
 CheckSimple2(76,3,ent.fragment,0)
-CheckSimple2(76,4,ent.in_fields,( "in1", ))
+CheckSimple2(76,4,ent.in_fields,( B("in1"), ))
 CheckSimple2(76,5,ent.numbits,2)
 CheckSimple2(76,6,ent.bitnum,3)
 
@@ -763,7 +778,7 @@ except:
 CheckSimple2(77,1,ent.field_type,pygetdata.SBIT_ENTRY)
 CheckSimple2(77,2,ent.field_type_name,"SBIT_ENTRY")
 CheckSimple2(77,3,ent.fragment,0)
-CheckSimple2(77,4,ent.in_fields,( "in2", ))
+CheckSimple2(77,4,ent.in_fields,( B("in2"), ))
 CheckSimple2(77,5,ent.numbits,5)
 CheckSimple2(77,6,ent.bitnum,4)
 
@@ -782,7 +797,7 @@ except:
 CheckSimple2(78,1,ent.field_type,pygetdata.MULTIPLY_ENTRY)
 CheckSimple2(78,2,ent.field_type_name,"MULTIPLY_ENTRY")
 CheckSimple2(78,3,ent.fragment,0)
-CheckSimple2(78,4,ent.in_fields,( "in3", "in2"))
+CheckSimple2(78,4,ent.in_fields,( B("in3"), B("in2")))
 
 # 79: add / entry (phase) check
 ent = pygetdata.entry(pygetdata.PHASE_ENTRY, "mnew10", 0,
@@ -799,7 +814,7 @@ except:
 CheckSimple2(79,1,ent.field_type,pygetdata.PHASE_ENTRY)
 CheckSimple2(79,2,ent.field_type_name,"PHASE_ENTRY")
 CheckSimple2(79,3,ent.fragment,0)
-CheckSimple2(79,4,ent.in_fields,( "in3", ))
+CheckSimple2(79,4,ent.in_fields,( B("in3"), ))
 CheckSimple2(79,5,ent.shift,44)
 
 # 80: add / entry (const) check
@@ -825,7 +840,7 @@ try:
   n = d.get_string("string")
 except:
   CheckOK(81)
-CheckSimple(81,n,"Zaphod Beeblebrox")
+CheckSimple(81,n,B("Zaphod Beeblebrox"))
 
 # 82: entry (string) check
 ent = pygetdata.entry(pygetdata.STRING_ENTRY, "new12", 0)
@@ -852,7 +867,7 @@ try:
   n = d.get_string("lorem")
 except:
   CheckOK2(84,2)
-CheckSimple(84,n,"Lorem ipsum")
+CheckSimple(84,n,B("Lorem ipsum"))
 
 # 85: madd_spec check
 try:
@@ -864,7 +879,7 @@ try:
   n = d.get_string("lorem/ipsum")
 except:
   CheckOK2(85,2)
-CheckSimple(85,n,"dolor sit amet.")
+CheckSimple(85,n,B("dolor sit amet."))
 
 # 86: put_constant / int check
 try:
@@ -880,7 +895,7 @@ CheckSimple(86,n,86)
 
 # 88: put_constant / int check
 try:
-  d.put_constant("const", 128L)
+  d.put_constant("const", L(128))
 except:
   CheckOK2(88,1)
 
@@ -888,11 +903,11 @@ try:
   n = d.get_constant("const",pygetdata.ULONG)
 except:
   CheckOK2(88,2)
-CheckSimple(88,n,128L)
+CheckSimple(88,n,L(128))
 
 # 89: put_constant / int check
 try:
-  d.put_constant("const", 89L)
+  d.put_constant("const", L(89))
 except:
   CheckOK2(89,1)
 
@@ -900,7 +915,7 @@ try:
   n = d.get_constant("const",pygetdata.LONG)
 except:
   CheckOK2(89,2)
-CheckSimple(89,n,89L)
+CheckSimple(89,n,L(89))
 
 # 91: put_constant / float check
 try:
@@ -936,7 +951,7 @@ try:
   n = d.get_string("string")
 except:
   CheckOK2(94,2)
-CheckSimple(94,n,"Arthur Dent")
+CheckSimple(94,n,B("Arthur Dent"))
 
 # 95: nmfields_by_type check
 try:
@@ -950,7 +965,7 @@ try:
   n = d.mfield_list("data",pygetdata.LINCOM_ENTRY)
 except:
   CheckOK(96)
-CheckSimple(96,n,["mnew1"])
+CheckSimple(96,n,[B("mnew1")])
 
 # 97: nmvectors check
 try:
@@ -964,8 +979,8 @@ try:
   n = d.mvector_list("data")
 except:
   CheckOK(98)
-CheckSimple(98,n,['mlut', 'mnew1', 'mnew3', 'mnew6', 'mnew7', 'mnew8', 'mnew9',
-  'mnew10'])
+CheckSimple(98,n,[B('mlut'), B('mnew1'), B('mnew3'), B('mnew6'), B('mnew7'),
+    B('mnew8'), B('mnew9'), B('mnew10')])
 
 # 99: alter / raw check
 ent = pygetdata.entry(pygetdata.RAW_ENTRY, "new1", 0,
@@ -1040,7 +1055,7 @@ except:
   CheckOK2(117,1)
 
 try:
-  CheckSimple(117,d.reference,"new1")
+  CheckSimple(117,d.reference,B("new1"))
 except:
   CheckOK2(117,2)
 
@@ -1077,7 +1092,7 @@ except:
 CheckSimple2(121,1,ent.field_type,pygetdata.PHASE_ENTRY)
 CheckSimple2(121,2,ent.field_type_name,"PHASE_ENTRY")
 CheckSimple2(121,3,ent.fragment,0)
-CheckSimple2(121,4,ent.in_fields,( "in5", ))
+CheckSimple2(121,4,ent.in_fields,( B("in5"), ))
 CheckSimple2(121,5,ent.shift,3)
 
 # 122: delete check
@@ -1104,7 +1119,7 @@ except:
 CheckSimple2(123,1,ent.field_type,pygetdata.PHASE_ENTRY)
 CheckSimple2(123,2,ent.field_type_name,"PHASE_ENTRY")
 CheckSimple2(123,3,ent.fragment,0)
-CheckSimple2(123,4,ent.in_fields,( "in4", ))
+CheckSimple2(123,4,ent.in_fields,( B("in4"), ))
 CheckSimple2(123,5,ent.shift,11)
 
 # 124: move check
@@ -1120,7 +1135,7 @@ except:
 CheckSimple2(124,1,ent.field_type,pygetdata.MULTIPLY_ENTRY)
 CheckSimple2(124,2,ent.field_type_name,"MULTIPLY_ENTRY")
 CheckSimple2(124,3,ent.fragment,1)
-CheckSimple2(124,4,ent.in_fields,( "in1", "in2"))
+CheckSimple2(124,4,ent.in_fields,( B("in1"), B("in2")))
 
 # 125: rename check
 try:
@@ -1140,7 +1155,7 @@ except:
 CheckSimple2(125,1,ent.field_type,pygetdata.MULTIPLY_ENTRY)
 CheckSimple2(125,2,ent.field_type_name,"MULTIPLY_ENTRY")
 CheckSimple2(125,3,ent.fragment,1)
-CheckSimple2(125,4,ent.in_fields,( "in1", "in2"))
+CheckSimple2(125,4,ent.in_fields,( B("in1"), B("in2")))
 
 # 126: uninclude check
 try:
@@ -1223,7 +1238,7 @@ except:
 CheckSimple2(143,1,ent.field_type,pygetdata.DIVIDE_ENTRY)
 CheckSimple2(143,2,ent.field_type_name,"DIVIDE_ENTRY")
 CheckSimple2(143,3,ent.fragment,0)
-CheckSimple2(143,4,ent.in_fields,( "mult", "bit"))
+CheckSimple2(143,4,ent.in_fields,( B("mult"), B("bit")))
 
 # 145: entry (recip) check
 try:
@@ -1233,7 +1248,7 @@ except:
 CheckSimple2(145,1,ent.field_type,pygetdata.RECIP_ENTRY)
 CheckSimple2(145,2,ent.field_type_name,"RECIP_ENTRY")
 CheckSimple2(145,3,ent.fragment,0)
-CheckSimple2(145,4,ent.in_fields,( "div",))
+CheckSimple2(145,4,ent.in_fields,( B("div"),))
 CheckSimple2(145,6,ent.dividend,6.5+4.3j)
 
 # 146: add / entry (divide) check
@@ -1249,7 +1264,7 @@ except:
   CheckOK2(146,2)
 CheckSimple2(146,1,ent.field_type,pygetdata.DIVIDE_ENTRY)
 CheckSimple2(146,2,ent.fragment,0)
-CheckSimple2(146,3,ent.in_fields,( "in1", "in2"))
+CheckSimple2(146,3,ent.in_fields,( B("in1"), B("in2")))
 
 # 148: add / entry (recip) check
 ent = pygetdata.entry(pygetdata.RECIP_ENTRY, "new16", 0, ("in3", 33.3))
@@ -1264,7 +1279,7 @@ except:
   CheckOK2(148,2)
 CheckSimple2(148,1,ent.field_type,pygetdata.RECIP_ENTRY)
 CheckSimple2(148,2,ent.fragment,0)
-CheckSimple2(148,3,ent.in_fields,( "in3",))
+CheckSimple2(148,3,ent.in_fields,( B("in3"),))
 CheckSimple2(148,4,ent.dividend,33.3)
 
 # 149: madd / entry (div) check
@@ -1281,7 +1296,7 @@ except:
   CheckOK2(149,2)
 CheckSimple2(149,1,ent.field_type,pygetdata.DIVIDE_ENTRY)
 CheckSimple2(149,2,ent.fragment,0)
-CheckSimple2(149,3,ent.in_fields,( "in3", "in2"))
+CheckSimple2(149,3,ent.in_fields,( B("in3"), B("in2")))
 
 # 151: madd / entry (recip) check
 ent = pygetdata.entry(pygetdata.RECIP_ENTRY, "mnew16", 0,
@@ -1297,8 +1312,8 @@ except:
   CheckOK2(151,2)
 CheckSimple2(151,1,ent.field_type,pygetdata.RECIP_ENTRY)
 CheckSimple2(151,2,ent.fragment,0)
-CheckSimple2(151,3,ent.in_fields,( "in3",))
-CheckSimple2(151,4,ent.dividend,"const")
+CheckSimple2(151,3,ent.in_fields,( B("in3"),))
+CheckSimple2(151,4,ent.dividend,B("const"))
 
 # 155: fragment.rewrite check
 try:
@@ -1356,7 +1371,7 @@ try:
 except:
   CheckOK(162)
 
-CheckNumpy(162,n,numpy.arange(3L,5L))
+CheckNumpy(162,n,numpy.arange(L(3),L(5)))
 
 # 163: gd_get_carray_slice (auto-type)
 try:
@@ -1389,7 +1404,7 @@ except:
   CheckOK(167)
 
 CheckSimple2(167,1,len(n),1)
-CheckSimple2(167,2,n[0][0],"carray")
+CheckSimple2(167,2,n[0][0],B("carray"))
 CheckNumpy2(167,3,n[0][1],numpy.arange(1,7))
 
 # 168: gd_put_carray
@@ -1420,7 +1435,7 @@ CheckNumpy(169,n,numpy.array([9,8,169,169,5,4]))
 
 # 172: gd_put_carray_slice (INT64)
 try:
-  d.put_carray("carray", [172L,172L], start=2)
+  d.put_carray("carray", [L(172),L(172)], start=2)
 except:
   CheckOK2(172,1)
 
@@ -1519,71 +1534,71 @@ try:
   n = d.constants(pygetdata.INT)
 except:
   CheckOK(183)
-CheckSimple(183,n,[('const', 93), ('new11', 0)])
+CheckSimple(183,n,[(B('const'), 93), (B('new11'), 0)])
 
 # 186: gd_constants (long)
 try:
   n = d.constants(pygetdata.LONG)
 except:
   CheckOK(186)
-CheckSimple(186,n,[('const', 93L), ('new11', 0L)])
+CheckSimple(186,n,[(B('const'), L(93)), (B('new11'), L(0))])
 
 # 188: gd_constants (float)
 try:
   n = d.constants(pygetdata.FLOAT)
 except:
   CheckOK(188)
-CheckSimple(188,n,[('const', 93.0), ('new11', 0.0)])
+CheckSimple(188,n,[(B('const'), 93.0), (B('new11'), 0.0)])
 
 # 190: gd_constants (complex)
 try:
   n = d.constants(pygetdata.COMPLEX)
 except:
   CheckOK(190)
-CheckSimple(190,n,[('const', 93.0), ('new11', 0.0)])
+CheckSimple(190,n,[(B('const'), 93.0), (B('new11'), 0.0)])
 
 # 191: gd_constants (int)
 try:
   n = d.mconstants("data", pygetdata.INT)
 except:
   CheckOK(191)
-CheckSimple(191,n,[('mconst', 3), ('mnew11', 0)])
+CheckSimple(191,n,[(B('mconst'), 3), (B('mnew11'), 0)])
 
 # 194: gd_constants (long)
 try:
   n = d.mconstants("data", pygetdata.LONG)
 except:
   CheckOK(194)
-CheckSimple(194,n,[('mconst', 3L), ('mnew11', 0L)])
+CheckSimple(194,n,[(B('mconst'), L(3)), (B('mnew11'), L(0))])
 
 # 196: gd_constants (float)
 try:
   n = d.mconstants("data", pygetdata.FLOAT)
 except:
   CheckOK(196)
-CheckSimple(196,n,[('mconst', 3.3), ('mnew11', 0.)])
+CheckSimple(196,n,[(B('mconst'), 3.3), (B('mnew11'), 0.)])
 
 # 198: gd_constants (complex)
 try:
   n = d.mconstants("data", pygetdata.COMPLEX)
 except:
   CheckOK(198)
-CheckSimple(198,n,[('mconst', 3.3+4.4j), ('mnew11', 0j)])
+CheckSimple(198,n,[(B('mconst'), 3.3+4.4j), (B('mnew11'), 0j)])
 
 # 199: gd_strings
 try:
   n = d.strings()
 except:
   CheckOK(199)
-CheckSimple(199,n,[('lorem', 'Lorem ipsum'), ('new12', ''), 
-  ('string', 'Arthur Dent')])
+CheckSimple(199,n,[(B('lorem'), B('Lorem ipsum')), (B('new12'), B('')), 
+  (B('string'), B('Arthur Dent'))])
 
 # 200: gd_strings
 try:
   n = d.mstrings("data")
 except:
   CheckOK(200)
-CheckSimple(200,n,[('mstr', 'This is a string constant.')])
+CheckSimple(200,n,[(B('mstr'), B('This is a string constant.'))])
 
 # 203: gd_seek
 try:
@@ -1663,7 +1678,7 @@ except:
 CheckSimple2(211, 1, ent.field_type, pygetdata.WINDOW_ENTRY)
 CheckSimple2(211, 2, ent.fragment, 0)
 CheckSimple2(211, 3, ent.windop, pygetdata.WINDOP_LT)
-CheckSimple2(211, 4, ent.in_fields, ( 'linterp', 'mult' ))
+CheckSimple2(211, 4, ent.in_fields, ( B('linterp'), B('mult') ))
 CheckSimple2(211, 5, ent.threshold, 4.1)
 
 # 212: gd_add_window check
@@ -1681,7 +1696,7 @@ except:
 CheckSimple2(212, 1, ent.field_type, pygetdata.WINDOW_ENTRY)
 CheckSimple2(212, 2, ent.fragment, 0)
 CheckSimple2(212, 3, ent.windop, pygetdata.WINDOP_NE)
-CheckSimple2(212, 4, ent.in_fields, ( 'in1', 'in2' ))
+CheckSimple2(212, 4, ent.in_fields, ( B('in1'), B('in2') ))
 CheckSimple2(212, 5, ent.threshold, 32)
 
 # 214: gd_madd_window check
@@ -1699,7 +1714,7 @@ except:
 CheckSimple2(214, 1, ent.field_type, pygetdata.WINDOW_ENTRY)
 CheckSimple2(214, 2, ent.fragment, 0)
 CheckSimple2(214, 3, ent.windop, pygetdata.WINDOP_SET)
-CheckSimple2(214, 4, ent.in_fields, ( 'in2', 'in3' ))
+CheckSimple2(214, 4, ent.in_fields, ( B('in2'), B('in3') ))
 CheckSimple2(214, 5, ent.threshold, 128)
 
 # 217: gd_alter_window check
@@ -1717,7 +1732,7 @@ except:
 CheckSimple2(217, 1, ent.field_type, pygetdata.WINDOW_ENTRY)
 CheckSimple2(217, 2, ent.fragment, 0)
 CheckSimple2(217, 3, ent.windop, pygetdata.WINDOP_GE)
-CheckSimple2(217, 4, ent.in_fields, ( 'in3', 'in4' ))
+CheckSimple2(217, 4, ent.in_fields, ( B('in3'), B('in4') ))
 CheckSimple2(217, 5, ent.threshold, 32e3)
 
 # 218: gd_alias_target check
@@ -1725,7 +1740,7 @@ try:
   str = d.alias_target('alias')
 except:
   CheckOK(218)
-CheckSimple(218, str, 'data')
+CheckSimple(218, str, B('data'))
 
 # 219: gd_add_alias check
 try:
@@ -1737,7 +1752,7 @@ try:
   str = d.alias_target('new20')
 except:
   CheckOK2(219, 2)
-CheckSimple(219, str, 'data')
+CheckSimple(219, str, B('data'))
 
 # 220: gd_madd_alias check
 try:
@@ -1749,7 +1764,7 @@ try:
   str = d.alias_target('data/mnew20')
 except:
   CheckOK2(220, 2)
-CheckSimple(220, str, 'data')
+CheckSimple(220, str, B('data'))
 
 # 221: gd_naliases check
 try:
@@ -1763,7 +1778,7 @@ try:
   n = d.aliases('data')
 except:
   CheckOK(222)
-CheckSimple(222, n, [ 'data', 'alias', 'data/mnew20', 'new20' ])
+CheckSimple(222, n, [ B('data'), B('alias'), B('data/mnew20'), B('new20') ])
 
 # 223: gd_include_affix check
 try:
@@ -1778,8 +1793,8 @@ try:
   m = d.fragment(1).suffix
 except:
   CheckOK(226)
-CheckSimple2(226, 1, n, "A")
-CheckSimple2(226, 2, m, "Z")
+CheckSimple2(226, 1, n, B("A"))
+CheckSimple2(226, 2, m, B("Z"))
 
 # 227: gd_alter_affixes check
 try:
@@ -1793,8 +1808,8 @@ try:
   m = d.fragment(1).suffix
 except:
   CheckOK2(227, 2)
-CheckSimple2(227, 1, n, "B")
-CheckSimple2(227, 2, m, "")
+CheckSimple2(227, 1, n, B("B"))
+CheckSimple2(227, 2, m, B(""))
 
 # 228: gd_entry (MPLEX) check
 try:
@@ -1804,7 +1819,7 @@ except:
 CheckSimple2(228, 1, ent.field_type, pygetdata.MPLEX_ENTRY)
 CheckSimple2(228, 2, ent.fragment, 0)
 CheckSimple2(228, 3, ent.count_val, 1)
-CheckSimple2(228, 4, ent.in_fields, ( 'data', 'sbit' ))
+CheckSimple2(228, 4, ent.in_fields, ( B('data'), B('sbit') ))
 CheckSimple2(228, 5, ent.period, 10)
 
 # 229: gd_add_mplex check
@@ -1821,7 +1836,7 @@ except:
 CheckSimple2(229, 1, ent.field_type, pygetdata.MPLEX_ENTRY)
 CheckSimple2(229, 2, ent.fragment, 0)
 CheckSimple2(229, 3, ent.count_val, 5)
-CheckSimple2(229, 4, ent.in_fields, ( 'in1', 'in2' ))
+CheckSimple2(229, 4, ent.in_fields, ( B('in1'), B('in2') ))
 CheckSimple2(229, 5, ent.period, 6)
 
 # 230: gd_madd_mplex check
@@ -1838,7 +1853,7 @@ except:
 CheckSimple2(230, 1, ent.field_type, pygetdata.MPLEX_ENTRY)
 CheckSimple2(230, 2, ent.fragment, 0)
 CheckSimple2(230, 3, ent.count_val, 0)
-CheckSimple2(230, 4, ent.in_fields, ( 'in2', 'in3' ))
+CheckSimple2(230, 4, ent.in_fields, ( B('in2'), B('in3') ))
 CheckSimple2(230, 5, ent.period, 12)
 
 # 231: gd_alter_mplex check
@@ -1856,7 +1871,7 @@ except:
 CheckSimple2(231, 1, ent.field_type, pygetdata.MPLEX_ENTRY)
 CheckSimple2(231, 2, ent.fragment, 0)
 CheckSimple2(231, 3, ent.count_val, 3)
-CheckSimple2(231, 4, ent.in_fields, ( 'in3', 'in4' ))
+CheckSimple2(231, 4, ent.in_fields, ( B('in3'), B('in4') ))
 CheckSimple2(231, 5, ent.period, 7)
 
 # 232: gd_strtok check
@@ -1864,13 +1879,13 @@ try:
   str = d.strtok("\"test1 test2\" test3\ test4")
 except:
   CheckOK2(232, 1)
-CheckSimple2(232, 2, str, "test1 test2")
+CheckSimple2(232, 2, str, B("test1 test2"))
 
 try:
   str = d.strtok()
 except:
   CheckOK2(232, 3)
-CheckSimple2(232, 4, str, "test3 test4")
+CheckSimple2(232, 4, str, B("test3 test4"))
 
 # 233: gd_raw_close check
 try:
@@ -1915,6 +1930,7 @@ try:
 except:
   CheckOK2(237, 1)
 CheckSimple2(237, 1, n, 5)
+#n = d.nentries(type = pygetdata.VECTOR_ENTRIES, flags = pygetdata.ENTRIES_HIDDEN | pygetdata.ENTRIES_NOALIAS)
 try:
   n = d.nentries(type = pygetdata.VECTOR_ENTRIES,
       flags = pygetdata.ENTRIES_HIDDEN | pygetdata.ENTRIES_NOALIAS)
@@ -1928,9 +1944,10 @@ try:
       flags = pygetdata.ENTRIES_HIDDEN | pygetdata.ENTRIES_NOALIAS)
 except:
   CheckOK(239)
-CheckSimple(239,n, ['INDEX', 'bit', 'data', 'div', 'lincom', 'linterp',
-  'mplex', 'mult', 'new1', 'new14', 'new16', 'new18', 'new2', 'new21', 'new4',
-  'new6', 'new7', 'new8', 'phase', 'polynom', 'recip', 'sbit', 'window'])
+CheckSimple(239,n, [B('INDEX'), B('bit'), B('data'), B('div'), B('lincom'),
+    B('linterp'), B('mplex'), B('mult'), B('new1'), B('new14'), B('new16'),
+    B('new18'), B('new2'), B('new21'), B('new4'), B('new6'), B('new7'),
+    B('new8'), B('phase'), B('polynom'), B('recip'), B('sbit'), B('window')])
 
 # 240: gd_mplex_lookback check
 try:
@@ -1958,9 +1975,9 @@ except:
   CheckOK(242)
 
 CheckSimple2(242,1,len(n),2)
-CheckSimple2(242,2,n[0][0],"mcarray")
+CheckSimple2(242,2,n[0][0],B("mcarray"))
 CheckNumpy2(242,3,n[0][1],1.9 + 0.9 * numpy.arange(0,5))
-CheckSimple2(242,4,n[1][0],"mnew17")
+CheckSimple2(242,4,n[1][0],B("mnew17"))
 CheckNumpy2(242,5,n[1][1],[0,0])
 
 # 271: encoding_support
@@ -1975,8 +1992,8 @@ except:
   CheckOK2(272, 1)
 
 try:
-  n = m.reference;
-  CheckSimple(272, n, None);
+  n = m.reference
+  CheckSimple(272, n, None)
 except:
   CheckOK2(272, 2)
 
@@ -1985,7 +2002,7 @@ try:
   n = d.get_carray("carray", pygetdata.NULL, start=2, len=2)
 except:
   CheckOK(274)
-CheckSimple(274, n, None);
+CheckSimple(274, n, None)
 
 
 
@@ -2007,5 +2024,5 @@ del d
 os.system("rm -rf dirfile")
 
 if (ne > 0):
-  print "ne =", ne
+  print ("ne =", ne)
   sys.exit(1)
diff --git a/bindings/python/test/callback.py b/bindings/python/test/callback.py
index 640fa0d..0c67da9 100644
--- a/bindings/python/test/callback.py
+++ b/bindings/python/test/callback.py
@@ -27,32 +27,32 @@ import pygetdata
 #callback
 def parser_callback(pdata, extra):
   if (extra != "extra stuff"):
-    print "extra =", extra;
+    print ("extra =", extra)
     sys.exit(1)
 
   if (pdata["suberror"] != 8):
-    print "suberror =", pdata["suberror"]
-    sys.exit(1);
+    print ("suberror =", pdata["suberror"])
+    sys.exit(1)
 
   if (pdata["line"] != "bad line\n"):
-    print "line =", pdata["line"]
-    sys.exit(1);
+    print ("line =", pdata["line"])
+    sys.exit(1)
 
   if (pdata["linenum"] != 2):
-    print "linenum =", pdata["linenum"]
-    sys.exit(1);
+    print ("linenum =", pdata["linenum"])
+    sys.exit(1)
 
   if (re.search("dirfile/format$", pdata["filename"]) == None):
-    print "filename =", pdata["filename"]
-    sys.exit(1);
+    print ("filename =", pdata["filename"])
+    sys.exit(1)
 
-  return pygetdata.SYNTAX_IGNORE;
+  return pygetdata.SYNTAX_IGNORE
 
 # create the dirfile first
 data=array.array("H",range(3,7000,7))
 os.system("rm -rf dirfile")
 os.mkdir("dirfile")
-file=open("dirfile/data", 'w')
+file=open("dirfile/data", 'wb')
 data.tofile(file)
 file.close()
 
@@ -61,11 +61,11 @@ file.write("data RAW UINT16 8\nbad line\n")
 file.close()
 
 d=pygetdata.dirfile("dirfile", pygetdata.RDONLY, callback=parser_callback,
-    extra="extra stuff");
-error=d.error;
+    extra="extra stuff")
+error=d.error
 
 os.system("rm -rf dirfile")
 
 if (error != pygetdata.E_OK):
-  print "error = ", error
+  print ("error = ", error)
   sys.exit(1)
diff --git a/bindings/python/test/char_enc1.py b/bindings/python/test/char_enc1.py
new file mode 100644
index 0000000..30ed38e
--- /dev/null
+++ b/bindings/python/test/char_enc1.py
@@ -0,0 +1,245 @@
+# Copyright (C) 2016 D. V. Wiebe
+#
+##########################################################################
+#
+# This file is part of the GetData project.
+#
+# GetData 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.
+#
+# GetData 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 GetData; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+# Test character_encoding
+
+import re
+import os
+import sys
+import pygetdata
+
+# Python2/3 abstraction:
+
+# an encoded string
+def B(s):
+  if sys.version[:1] == '3':
+    return bytes(s, "UTF-8")
+  return s
+
+# a decoded string
+def U(s):
+  if sys.version[:1] == '3':
+    return s
+  return unicode(s)
+
+ne = 0
+
+def CheckOK(t):
+  global ne
+  ne+=1
+  print ("e[", t, "] =", sys.exc_info()[0], sys.exc_value)
+
+def CheckSimple(t,v,g):
+  global ne
+  if (v != g):
+    ne+=1
+    print ("n[", t, "] =", v, "expected", g)
+
+def CheckEOS(t,v,g):
+  global ne
+  if (U(v)[-len(U(g)):] != U(g)):
+    ne+=1
+    print ("n[", t, "] =", repr(v), "expected", repr(g))
+
+# create the dirfile
+os.system("rm -rf dirfile")
+os.mkdir("dirfile")
+
+# Encoded string (koi8-r)
+estring =  B('\xF3\xD4\xD2\xCF\xCB\xC1')
+
+# byte-escaped (used for Dirfile metadata)
+xstring = B('\\xF3\\xD4\\xD2\\xCF\\xCB\\xC1')
+
+# The decoded version
+ustring = unichr(0x421) + unichr(0x442) + unichr(0x440) + unichr(0x43E) + \
+    unichr(0x43A) + unichr(0x430)
+
+# Unicode escaped, which will show up in ASCII-ified error messages
+xustring = B("\\u0421\\u0442\\u0440\\u043e\\u043a\\u0430")
+
+f=open("dirfile/format", "wb")
+f.write(
+        B("/ALIAS ") + xstring + B("_al ") + xstring + B("_t\n") +
+        xstring + B("_s1 STRING ") + xstring + B("1\n") +
+        xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_c1 CONST UINT8 1\n") +
+        xstring + B("_c2 CONST UINT8 1\n") +
+        xstring + B("_r1 RAW UINT8 ") + xstring + B("_spf\n") +
+        B("l1 LINTERP in ") + xstring + B("\n") +
+        B("l1/") + xstring + B("_s1 STRING ") + xstring + B("1\n") +
+        B("l1/") + xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        B("l1/") + xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_c1 CONST UINT8 1\n") +
+        B("l1/") + xstring + B("_c2 CONST UINT8 2\n") +
+        B("o1 LINCOM ") + xstring + B("_i ") + xstring + B("_m ") +
+        xstring + B("_b\n") +
+        B("o2 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2\n") +
+        B("o3 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2 ") +
+        xstring + B("_i3 ") + xstring + B("_m3 ") + xstring + B("_b3\n") +
+        B("b1 BIT ") + xstring + B("_i ") +
+        xstring + B("_bn ") + xstring + B("_nb\n") +
+        B("e1 RECIP in ") + xstring + B("_dv\n") +
+        B("p1 PHASE ") + xstring + B("_i ") + xstring + B("_ps\n") +
+        B("m1 MPLEX a b ") + xstring + B("_cv ") + xstring + B("_pd\n") +
+        B("y1 POLYNOM ") + xstring + B("_i ") + xstring + B("_y1 2 ") +
+        xstring + B("_y3\n") +
+        B("w1 WINDOW a b EQ ") + xstring + B("_t1\n") +
+        B("w2 WINDOW a b SET ") + xstring + B("_t2\n") +
+        B("w3 WINDOW a b GT ") + xstring + B("_t3\n") +
+        B("d1 DIVIDE ") + xstring + B("_i1 ") + xstring + B("_i2\n")
+        )
+f.close()
+
+try:
+  D=pygetdata.dirfile("dirfile", pygetdata.RDONLY)
+except pygetdata.DirfileError:
+  CheckOK(0)
+
+# Attempt 1: use the correct character encoding
+D.character_encoding = 'koi8_r'
+
+CheckSimple(1,D.character_encoding,'koi8_r')
+
+try:
+  D.validate(estring)
+except pygetdata.DirfileError:
+  CheckEOS(2,D.error_string,xustring)
+
+c = D.carrays(return_type=pygetdata.NULL)
+CheckSimple(3,len(c),2)
+CheckSimple(4,c[0][0],ustring + "_a1")
+CheckSimple(5,c[1][0],ustring + "_a2")
+
+c = D.constants(return_type=pygetdata.UINT8)
+CheckSimple(6,len(c),2)
+CheckSimple(7,c[0][0],ustring + "_c1")
+CheckSimple(8,c[1][0],ustring + "_c2")
+
+c = D.mcarrays("l1", return_type=pygetdata.NULL)
+CheckSimple(9,len(c),2)
+CheckSimple(10,c[0][0], ustring + "_a1")
+CheckSimple(11,c[1][0], ustring + "_a2")
+
+c = D.mconstants("l1", return_type=pygetdata.UINT8)
+CheckSimple(12,len(c),2)
+CheckSimple(13,c[0][0], ustring + "_c1")
+CheckSimple(14,c[1][0], ustring + "_c2")
+
+c = D.strings()
+CheckSimple(15,len(c),2)
+CheckSimple(16,c[0][0], ustring + "_s1")
+CheckSimple(17,c[0][1], ustring + "1")
+CheckSimple(18,c[0][0], ustring + "_s1")
+CheckSimple(19,c[1][1], ustring + "2")
+
+c = D.mstrings("l1")
+CheckSimple(20,len(c),2)
+CheckSimple(21,c[0][0], ustring + "_s1")
+CheckSimple(22,c[0][1], ustring + "1")
+CheckSimple(23,c[0][0], ustring + "_s1")
+CheckSimple(24,c[1][1], ustring + "2")
+
+c = D.reference
+CheckSimple(25,c,ustring + "_r1")
+
+c = D.get_string(ustring + "_s1")
+CheckSimple(26,c,ustring + "1")
+
+c = D.alias_target(ustring + "_al")
+CheckSimple(27,c,ustring + "_t")
+
+c = D.entry(ustring + "_r1")
+CheckSimple(28,c.name,ustring + "_r1")
+CheckSimple(29,c.spf,ustring + "_spf")
+CheckSimple(30,c.parameters,(1, ustring + "_spf"))
+
+c = D.entry("l1")
+CheckSimple(31,c.parameters,("in", estring))
+
+c = D.entry("d1")
+CheckSimple(32,c.in_fields,(ustring + "_i1", ustring + "_i2"))
+CheckSimple(33,c.parameters,(ustring + "_i1", ustring + "_i2"))
+
+c = D.entry("e1")
+CheckSimple(35,c.dividend,ustring + "_dv")
+CheckSimple(36,c.parameters,("in", ustring + "_dv"))
+
+c = D.entry("p1")
+CheckSimple(37,c.in_fields,(ustring + "_i",))
+CheckSimple(38,c.shift,ustring + "_ps")
+CheckSimple(39,c.parameters,(ustring + "_i", ustring + "_ps"))
+
+c = D.entry("y1")
+CheckSimple(40,c.a,(ustring + "_y1", 2, ustring + "_y3"))
+CheckSimple(41,c.parameters,(ustring + "_i",
+  (ustring + "_y1", 2, ustring + "_y3")))
+
+c = D.entry("o1")
+CheckSimple(42,c.in_fields,(ustring + "_i",))
+CheckSimple(43,c.m,(ustring + "_m",))
+CheckSimple(44,c.b,(ustring + "_b",))
+CheckSimple(45,c.parameters,((ustring + "_i",), (ustring + "_m",),
+  (ustring + "_b",)))
+
+c = D.entry("o2")
+CheckSimple(46,c.in_fields,(ustring + "_i1",ustring + "_i2"))
+CheckSimple(47,c.m,(ustring + "_m1",ustring + "_m2"))
+CheckSimple(48,c.b,(ustring + "_b1",ustring + "_b2"))
+CheckSimple(49,c.parameters,((ustring + "_i1",ustring + "_i2"),
+  (ustring + "_m1",ustring + "_m2"),(ustring + "_b1",ustring + "_b2")))
+
+c = D.entry("o3")
+CheckSimple(50,c.in_fields,(ustring + "_i1",ustring + "_i2",ustring + "_i3"))
+CheckSimple(51,c.m,(ustring + "_m1",ustring + "_m2",ustring + "_m3"))
+CheckSimple(52,c.b,(ustring + "_b1",ustring + "_b2",ustring + "_b3"))
+CheckSimple(53,c.parameters,((ustring + "_i1",ustring + "_i2",ustring + "_i3"),
+  (ustring + "_m1",ustring + "_m2",ustring + "_m3"),
+  (ustring + "_b1",ustring + "_b2",ustring + "_b3")))
+
+c = D.entry("w1")
+CheckSimple(54,c.parameters,("a", "b", pygetdata.WINDOP_EQ, ustring + "_t1"))
+
+c = D.entry("w2")
+CheckSimple(55,c.parameters,("a", "b", pygetdata.WINDOP_SET, ustring + "_t2"))
+
+c = D.entry("w3")
+CheckSimple(56,c.parameters,("a", "b", pygetdata.WINDOP_GT, ustring + "_t3"))
+
+c = D.entry("m1")
+CheckSimple(57,c.count_val, ustring + "_cv")
+CheckSimple(58,c.period, ustring + "_pd")
+CheckSimple(59,c.parameters,("a", "b", ustring + "_cv", ustring + "_pd"))
+
+D.discard()
+del D
+os.system("rm -rf dirfile")
+
+if (ne > 0):
+  print ("ne = ",ne)
+  sys.exit(1)
+  
diff --git a/bindings/python/test/char_enc2.py b/bindings/python/test/char_enc2.py
new file mode 100644
index 0000000..9fd7ddd
--- /dev/null
+++ b/bindings/python/test/char_enc2.py
@@ -0,0 +1,242 @@
+# Copyright (C) 2016 D. V. Wiebe
+#
+##########################################################################
+#
+# This file is part of the GetData project.
+#
+# GetData 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.
+#
+# GetData 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 GetData; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+# Test character_encoding
+
+import re
+import os
+import sys
+import pygetdata
+
+# Python2/3 abstraction:
+
+# an encoded string
+def B(s):
+  if sys.version[:1] == '3':
+    return bytes(s, "UTF-8")
+  return s
+
+# a decoded string
+def U(s):
+  if sys.version[:1] == '3':
+    return s
+  return unicode(s)
+
+ne = 0
+
+def CheckOK(t):
+  global ne
+  ne+=1
+  print ("e[", t, "] =", sys.exc_info()[0], sys.exc_value)
+
+def CheckSimple(t,v,g):
+  global ne
+  if (v != g):
+    ne+=1
+    print ("n[", t, "] =", v, "expected", g)
+
+def CheckEOS(t,v,g):
+  global ne
+  if (v[-len(g):] != g):
+    ne+=1
+    print ("n[", t, "] =", repr(v), "expected", repr(g))
+
+# create the dirfile
+os.system("rm -rf dirfile")
+os.mkdir("dirfile")
+
+# Encoded string (koi8-r)
+estring =  B('\xF3\xD4\xD2\xCF\xCB\xC1')
+
+# byte-escaped (used for Dirfile metadata)
+xstring = B('\\xF3\\xD4\\xD2\\xCF\\xCB\\xC1')
+
+# The decoded version
+ustring = unichr(0x421) + unichr(0x442) + unichr(0x440) + unichr(0x43E) + \
+    unichr(0x43A) + unichr(0x430)
+
+# Unicode escaped, which will show up in ASCII-ified error messages
+xestring = B("\\u0421\\u0442\\u0440\\u043e\\u043a\\u0430")
+
+f=open("dirfile/format", "wb")
+f.write(
+        B("/ALIAS ") + xstring + B("_al ") + xstring + B("_t\n") +
+        xstring + B("_s1 STRING ") + xstring + B("1\n") +
+        xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_c1 CONST UINT8 1\n") +
+        xstring + B("_c2 CONST UINT8 1\n") +
+        xstring + B("_r1 RAW UINT8 ") + xstring + B("_spf\n") +
+        B("l1 LINTERP in ") + xstring + B("\n") +
+        B("l1/") + xstring + B("_s1 STRING ") + xstring + B("1\n") +
+        B("l1/") + xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        B("l1/") + xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_c1 CONST UINT8 1\n") +
+        B("l1/") + xstring + B("_c2 CONST UINT8 2\n") +
+        B("o1 LINCOM ") + xstring + B("_i ") + xstring + B("_m ") +
+        xstring + B("_b\n") +
+        B("o2 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2\n") +
+        B("o3 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2 ") +
+        xstring + B("_i3 ") + xstring + B("_m3 ") + xstring + B("_b3\n") +
+        B("b1 BIT ") + xstring + B("_i ") +
+        xstring + B("_bn ") + xstring + B("_nb\n") +
+        B("e1 RECIP in ") + xstring + B("_dv\n") +
+        B("p1 PHASE ") + xstring + B("_i ") + xstring + B("_ps\n") +
+        B("m1 MPLEX a b ") + xstring + B("_cv ") + xstring + B("_pd\n") +
+        B("y1 POLYNOM ") + xstring + B("_i ") + xstring + B("_y1 2 ") +
+        xstring + B("_y3\n") +
+        B("w1 WINDOW a b EQ ") + xstring + B("_t1\n") +
+        B("w2 WINDOW a b SET ") + xstring + B("_t2\n") +
+        B("w3 WINDOW a b GT ") + xstring + B("_t3\n") +
+        B("d1 DIVIDE ") + xstring + B("_i1 ") + xstring + B("_i2\n")
+        )
+f.close()
+
+try:
+  D=pygetdata.dirfile("dirfile", pygetdata.RDONLY)
+except pygetdata.DirfileError:
+  CheckOK(0)
+
+# Attempt 2: no encoding
+
+try:
+  D.validate(estring)
+except pygetdata.DirfileError:
+  CheckEOS(2,D.error_string,estring)
+
+c = D.carrays(return_type=pygetdata.NULL)
+CheckSimple(3,len(c),2)
+CheckSimple(4,c[0][0],estring + "_a1")
+CheckSimple(5,c[1][0],estring + "_a2")
+
+c = D.constants(return_type=pygetdata.UINT8)
+CheckSimple(6,len(c),2)
+CheckSimple(7,c[0][0],estring + "_c1")
+CheckSimple(8,c[1][0],estring + "_c2")
+
+c = D.mcarrays("l1", return_type=pygetdata.NULL)
+CheckSimple(9,len(c),2)
+CheckSimple(10,c[0][0], estring + "_a1")
+CheckSimple(11,c[1][0], estring + "_a2")
+
+c = D.mconstants("l1", return_type=pygetdata.UINT8)
+CheckSimple(12,len(c),2)
+CheckSimple(13,c[0][0], estring + "_c1")
+CheckSimple(14,c[1][0], estring + "_c2")
+
+c = D.strings()
+CheckSimple(15,len(c),2)
+CheckSimple(16,c[0][0], estring + "_s1")
+CheckSimple(17,c[0][1], estring + "1")
+CheckSimple(18,c[0][0], estring + "_s1")
+CheckSimple(19,c[1][1], estring + "2")
+
+c = D.mstrings("l1")
+CheckSimple(20,len(c),2)
+CheckSimple(21,c[0][0], estring + "_s1")
+CheckSimple(22,c[0][1], estring + "1")
+CheckSimple(23,c[0][0], estring + "_s1")
+CheckSimple(24,c[1][1], estring + "2")
+
+c = D.reference
+CheckSimple(25,c,estring + "_r1")
+
+c = D.get_string(estring + "_s1")
+CheckSimple(26,c,estring + "1")
+
+c = D.alias_target(estring + "_al")
+CheckSimple(27,c,estring + "_t")
+
+c = D.entry(estring + "_r1")
+CheckSimple(28,c.name,estring + "_r1")
+CheckSimple(29,c.spf,estring + "_spf")
+CheckSimple(30,c.parameters,(1, estring + "_spf"))
+
+c = D.entry("l1")
+CheckSimple(31,c.parameters,("in", estring))
+
+c = D.entry("d1")
+CheckSimple(32,c.in_fields,(estring + "_i1", estring + "_i2"))
+CheckSimple(33,c.parameters,(estring + "_i1", estring + "_i2"))
+
+c = D.entry("e1")
+CheckSimple(35,c.dividend,estring + "_dv")
+CheckSimple(36,c.parameters,("in", estring + "_dv"))
+
+c = D.entry("p1")
+CheckSimple(37,c.in_fields,(estring + "_i",))
+CheckSimple(38,c.shift,estring + "_ps")
+CheckSimple(39,c.parameters,(estring + "_i", estring + "_ps"))
+
+c = D.entry("y1")
+CheckSimple(40,c.a,(estring + "_y1", 2, estring + "_y3"))
+CheckSimple(41,c.parameters,(estring + "_i",
+  (estring + "_y1", 2, estring + "_y3")))
+
+c = D.entry("o1")
+CheckSimple(42,c.in_fields,(estring + "_i",))
+CheckSimple(43,c.m,(estring + "_m",))
+CheckSimple(44,c.b,(estring + "_b",))
+CheckSimple(45,c.parameters,((estring + "_i",), (estring + "_m",),
+  (estring + "_b",)))
+
+c = D.entry("o2")
+CheckSimple(46,c.in_fields,(estring + "_i1",estring + "_i2"))
+CheckSimple(47,c.m,(estring + "_m1",estring + "_m2"))
+CheckSimple(48,c.b,(estring + "_b1",estring + "_b2"))
+CheckSimple(49,c.parameters,((estring + "_i1",estring + "_i2"),
+  (estring + "_m1",estring + "_m2"),(estring + "_b1",estring + "_b2")))
+
+c = D.entry("o3")
+CheckSimple(50,c.in_fields,(estring + "_i1",estring + "_i2",estring + "_i3"))
+CheckSimple(51,c.m,(estring + "_m1",estring + "_m2",estring + "_m3"))
+CheckSimple(52,c.b,(estring + "_b1",estring + "_b2",estring + "_b3"))
+CheckSimple(53,c.parameters,((estring + "_i1",estring + "_i2",estring + "_i3"),
+  (estring + "_m1",estring + "_m2",estring + "_m3"),
+  (estring + "_b1",estring + "_b2",estring + "_b3")))
+
+c = D.entry("w1")
+CheckSimple(54,c.parameters,("a", "b", pygetdata.WINDOP_EQ, estring + "_t1"))
+
+c = D.entry("w2")
+CheckSimple(55,c.parameters,("a", "b", pygetdata.WINDOP_SET, estring + "_t2"))
+
+c = D.entry("w3")
+CheckSimple(56,c.parameters,("a", "b", pygetdata.WINDOP_GT, estring + "_t3"))
+
+c = D.entry("m1")
+CheckSimple(57,c.count_val, estring + "_cv")
+CheckSimple(58,c.period, estring + "_pd")
+CheckSimple(59,c.parameters,("a", "b", estring + "_cv", estring + "_pd"))
+
+D.discard()
+del D
+os.system("rm -rf dirfile")
+
+if (ne > 0):
+  print ("ne = ",ne)
+  sys.exit(1)
+  
diff --git a/bindings/python/test/char_enc3.py b/bindings/python/test/char_enc3.py
new file mode 100644
index 0000000..dad11b8
--- /dev/null
+++ b/bindings/python/test/char_enc3.py
@@ -0,0 +1,366 @@
+# Copyright (C) 2016 D. V. Wiebe
+#
+##########################################################################
+#
+# This file is part of the GetData project.
+#
+# GetData 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.
+#
+# GetData 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 GetData; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+# Test character_encoding
+
+import re
+import os
+import sys
+import pygetdata
+
+# Python2/3 abstraction:
+
+# an encoded string
+def B(s):
+  if sys.version[:1] == '3':
+    return bytes(s, "UTF-8")
+  return s
+
+# a decoded string
+def U(s):
+  if sys.version[:1] == '3':
+    return s
+  return unicode(s)
+
+ne = 0
+
+def CheckOK(t):
+  global ne
+  ne+=1
+  print ("e[", t, "] =", sys.exc_info()[0], sys.exc_value)
+
+def CheckSimple(t,v,g):
+  global ne
+  if (v != g):
+    ne+=1
+    print ("n[", t, "] =", v, "expected", g)
+
+def CheckEOS(t,v,g):
+  global ne
+  if (v[-len(g):] != g):
+    ne+=1
+    print ("n[", t, "] =", repr(v), "expected", repr(g))
+
+def CheckExc(n):
+  global ne
+  global e
+  if (e):
+    e=0
+    ne+=1
+    print ("Missing UnicodeDecodeError for " + str(n))
+
+def CheckParms(n,c):
+  global e
+  try:
+    e = 1
+    print (c.parameters)
+  except UnicodeDecodeError:
+    e = 0
+
+  CheckExc(n)
+
+def CheckIns(n,c):
+  global e
+  try:
+    e = 1
+    print (c.in_fields)
+  except UnicodeDecodeError:
+    e = 0
+
+  CheckExc(n)
+
+# create the dirfile
+os.system("rm -rf dirfile")
+os.mkdir("dirfile")
+
+# Encoded string (koi8-r)
+estring =  B('\xF3\xD4\xD2\xCF\xCB\xC1')
+
+# byte-escaped (used for Dirfile metadata)
+xstring = B('\\xF3\\xD4\\xD2\\xCF\\xCB\\xC1')
+
+# Unicode escaped, which will show up in ASCII-ified error messages
+xustring = B("\\u0421\\u0442\\u0440\\u043e\\u043a\\u0430")
+
+f=open("dirfile/format", "wb")
+f.write(
+        B("/ALIAS ") + xstring + B("_al ") + xstring + B("_t\n") +
+        B("s1 STRING ") + xstring + B("1\n") +
+        xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        xstring + B("_c1 CONST UINT8 1\n") +
+        xstring + B("_c2 CONST UINT8 1\n") +
+        xstring + B("_r1 RAW UINT8 ") + xstring + B("_spf\n") +
+        B("r2 RAW UINT8 ") + xstring + B("_spf\n") +
+        B("l1 LINTERP in ") + xstring + B("\n") +
+        B("l1/") + xstring + B("_s1 STRING ") + xstring + B("1\n") +
+        B("l1/") + xstring + B("_s2 STRING ") + xstring + B("2\n") +
+        B("l1/") + xstring + B("_a1 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_a2 CARRAY UINT64 1 2 3\n") +
+        B("l1/") + xstring + B("_c1 CONST UINT8 1\n") +
+        B("l1/") + xstring + B("_c2 CONST UINT8 2\n") +
+        B("o1 LINCOM ") + xstring + B("_i ") + xstring + B("_m ") +
+        xstring + B("_b\n") +
+        B("o2 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2\n") +
+        B("o3 LINCOM ") +
+        xstring + B("_i1 ") + xstring + B("_m1 ") + xstring + B("_b1 ") +
+        xstring + B("_i2 ") + xstring + B("_m2 ") + xstring + B("_b2 ") +
+        xstring + B("_i3 ") + xstring + B("_m3 ") + xstring + B("_b3\n") +
+        B("b1 BIT ") + xstring + B("_i ") +
+        xstring + B("_bn ") + xstring + B("_nb\n") +
+        B("e1 RECIP in ") + xstring + B("_dv\n") +
+        B("p1 PHASE ") + xstring + B("_i ") + xstring + B("_ps\n") +
+        B("m1 MPLEX a b ") + xstring + B("_cv ") + xstring + B("_pd\n") +
+        B("y1 POLYNOM ") + xstring + B("_i ") + xstring + B("_y1 2 ") +
+        xstring + B("_y3\n") +
+        B("w1 WINDOW a b EQ ") + xstring + B("_t1\n") +
+        B("w2 WINDOW a b SET ") + xstring + B("_t2\n") +
+        B("w3 WINDOW a b GT ") + xstring + B("_t3\n") +
+        B("d1 DIVIDE ") + xstring + B("_i1 ") + xstring + B("_i2\n")
+        )
+f.close()
+
+try:
+  D=pygetdata.dirfile("dirfile", pygetdata.RDONLY)
+except pygetdata.DirfileError:
+  CheckOK(0)
+
+# Attempt 3: use an incorrect correct character encoding
+D.character_encoding = 'utf-8'
+
+CheckSimple(1,D.character_encoding,'utf-8')
+
+try:
+  D.validate(estring)
+except pygetdata.DirfileError:
+  CheckEOS(2,D.error_string,estring)
+
+try:
+  e = 1
+  c = D.carrays(return_type=pygetdata.NULL)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(0)
+
+try:
+  e = 1
+  c = D.constants(return_type=pygetdata.UINT8)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(1)
+
+try:
+  e = 1
+  c = D.mcarrays("l1", return_type=pygetdata.NULL)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(2)
+
+try:
+  e = 1
+  c = D.mconstants("l1", return_type=pygetdata.UINT8)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(2)
+
+try:
+  e = 1
+  c = D.strings()
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(3)
+
+try:
+  e = 1
+  c = D.mstrings("l1")
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(4)
+
+try:
+  e = 1
+  c = D.reference
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(5)
+
+try:
+  e = 1
+  c = D.get_string("s1")
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(6)
+
+try:
+  e = 1
+  c = D.alias_target(estring + "_al")
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(7)
+
+c = D.entry("r2")
+try:
+  e = 1
+  print (c.spf)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(8)
+CheckParms(9,c)
+
+# This works because LINTERP table is FS encoded
+c = D.entry("l1")
+CheckSimple(10,c.parameters,("in", estring))
+
+c = D.entry("d1")
+CheckIns(11, c)
+CheckParms(12,c)
+
+c = D.entry("e1")
+try:
+  e = 1
+  print (c.dividend)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(13)
+CheckParms(14,c)
+
+c = D.entry("p1")
+try:
+  e = 1
+  print (c.shift)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(15)
+CheckIns(16,c)
+CheckParms(17,c)
+
+c = D.entry("y1")
+try:
+  e = 1
+  print (c.a)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(18)
+CheckParms(19, c)
+
+c = D.entry("o1")
+try:
+  e = 1
+  print (c.m)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(20)
+try:
+  e = 1
+  print (c.b)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(21)
+CheckIns(22,c)
+CheckParms(23,c)
+
+c = D.entry("o2")
+try:
+  e = 1
+  print (c.m)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(24)
+try:
+  e = 1
+  print (c.b)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(25)
+CheckIns(26,c)
+CheckParms(27,c)
+
+c = D.entry("o3")
+try:
+  e = 1
+  print (c.m)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(28)
+try:
+  e = 1
+  print (c.b)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(29)
+CheckIns(30,c)
+CheckParms(31,c)
+
+c = D.entry("w1")
+CheckParms(32,c)
+
+c = D.entry("w2")
+CheckParms(33,c)
+
+c = D.entry("w3")
+CheckParms(34,c)
+
+c = D.entry("m1")
+try:
+  e = 1
+  print (c.count_val)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(35)
+try:
+  e = 1
+  print (c.period)
+except UnicodeDecodeError:
+  e = 0
+
+CheckExc(36)
+CheckParms(35,c)
+
+D.discard()
+del D
+os.system("rm -rf dirfile")
+
+if (ne > 0):
+  print ("ne = ",ne)
+  sys.exit(1)
+  
diff --git a/configure b/configure
index 301d2ca..da3b768 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for GetData 0.9.2.1.
+# Generated by GNU Autoconf 2.69 for GetData 0.9.3.
 #
 # Report bugs to <getdata-devel at lists.sourceforge.net>.
 #
@@ -598,8 +598,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='GetData'
 PACKAGE_TARNAME='getdata'
-PACKAGE_VERSION='0.9.2.1'
-PACKAGE_STRING='GetData 0.9.2.1'
+PACKAGE_VERSION='0.9.3'
+PACKAGE_STRING='GetData 0.9.3'
 PACKAGE_BUGREPORT='getdata-devel at lists.sourceforge.net'
 PACKAGE_URL='http://getdata.sourceforge.net/'
 
@@ -670,6 +670,8 @@ MAKE_PERLBINDINGS_FALSE
 MAKE_PERLBINDINGS_TRUE
 MAKE_IDLBINDINGS_FALSE
 MAKE_IDLBINDINGS_TRUE
+MAKE_PYGETDATA_CAPI_FALSE
+MAKE_PYGETDATA_CAPI_TRUE
 MAKE_PYBINDINGS_FALSE
 MAKE_PYBINDINGS_TRUE
 MAKE_F95BINDINGS_FALSE
@@ -730,6 +732,7 @@ path_bzip2
 BZIP2_LIBS
 BZIP2_LDFLAGS
 BZIP2_CPPFLAGS
+PYTHON_OBJECT_SUFFIX
 pythondir
 PYTHON_PLATFORM
 PYTHON_VERSION
@@ -752,6 +755,7 @@ MEX
 IDL_LIBS
 IDL_CFLAGS
 idldir
+idl_prefix
 IDL
 DEFINE_gd_uint64_t
 DEFINE_gd_int64_t
@@ -807,6 +811,7 @@ CCASFLAGS
 CCAS
 DEFINE_GD_NO_C99_API
 EGREP
+GREP
 CPP
 am__fastdepCC_FALSE
 am__fastdepCC_TRUE
@@ -836,7 +841,6 @@ JOT
 DIFF
 DATE
 SED
-GREP
 LN_S
 AM_BACKSLASH
 AM_DEFAULT_VERBOSITY
@@ -942,8 +946,8 @@ enable_fortran95
 enable_idl
 enable_matlab
 enable_perl
-enable_php
 enable_python
+enable_php
 enable_modules
 with_module_dir
 with_ltdl
@@ -1544,7 +1548,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures GetData 0.9.2.1 to adapt to many kinds of systems.
+\`configure' configures GetData 0.9.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1614,7 +1618,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of GetData 0.9.2.1:";;
+     short | recursive ) echo "Configuration of GetData 0.9.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1622,7 +1626,7 @@ Optional Features:
   --disable-option-checking  ignore unrecognized --enable/--with options
   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --enaable-legacy-api    include the legacy API wrapper in the library
+  --enable-legacy-api     include the legacy API wrapper in the library
   --enable-assert         enable assertions
   --enable-debug          enable debugging messages
   --enable-ansi-c         use ANSI C (C89) work-arounds for C99 code
@@ -1637,8 +1641,8 @@ Optional Features:
                           bindings (IDL_GetData)
   --disable-matlab        don't build the MATLAB bindings
   --disable-perl          don't build the Perl bindings (GetData)
-  --disable-php           don't build the PHP bindings
   --disable-python        don't build the Python bindings (pygetdata)
+  --disable-php           don't build the PHP bindings
   --enable-modules        build external encodings in dynamically loaded
                           modules instead of directly into the core GetData
                           library
@@ -1835,7 +1839,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-GetData configure 0.9.2.1
+GetData configure 0.9.3
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3010,7 +3014,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by GetData $as_me 0.9.2.1, which was
+It was created by GetData $as_me 0.9.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3368,7 +3372,7 @@ $as_echo "#define GETDATA_MAJOR 0" >>confdefs.h
 $as_echo "#define GETDATA_MINOR 9" >>confdefs.h
 
 
-$as_echo "#define GETDATA_REVISION 2" >>confdefs.h
+$as_echo "#define GETDATA_REVISION 3" >>confdefs.h
 
 
 $as_echo "#define GETDATA_VERSION_SUFFIX \"\"" >>confdefs.h
@@ -3378,11 +3382,11 @@ GETDATA_MAJOR=0
 
 GETDATA_MINOR=9
 
-GETDATA_REVISION=2
+GETDATA_REVISION=3
 
 GETDATA_VERSION_SUFFIX=
 
-GETDATA_LIB_VERSION=0.9.2
+GETDATA_LIB_VERSION=0.9.3
 
 
 
@@ -3394,11 +3398,11 @@ GETDATA_LIB_VERSION=0.9.2
 
 GETDATA_IFACE_VERSION=7
 
-GETDATA_IMPL_REVISION=2
+GETDATA_IMPL_REVISION=3
 
 GETDATA_IFACE_AGE=0
 
-GETDATAXX_VERSION=6:0:0
+GETDATAXX_VERSION=6:1:0
 
 FGETDATA_VERSION=5:0:0
 
@@ -3760,17 +3764,6 @@ $as_echo_n "checking whether to include the Perl bindings... " >&6; }
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $make_perlbindings" >&5
 $as_echo "$make_perlbindings" >&6; }
 
-# Check whether --enable-php was given.
-if test "${enable_php+set}" = set; then :
-  enableval=$enable_php;
-               case "${enableval}" in
-                 no) make_phpbindings="no" ;;
-                 *) make_phpbindings="yes" ;;
-               esac
-
-fi
-
-
 # Check whether --enable-python was given.
 if test "${enable_python+set}" = set; then :
   enableval=$enable_python;
@@ -3787,6 +3780,17 @@ $as_echo_n "checking whether to include the Python bindings... " >&6; }
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $make_pybindings" >&5
 $as_echo "$make_pybindings" >&6; }
 
+# Check whether --enable-php was given.
+if test "${enable_php+set}" = set; then :
+  enableval=$enable_php;
+               case "${enableval}" in
+                 no) make_phpbindings="no" ;;
+                 *) make_phpbindings="yes" ;;
+               esac
+
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include the PHP bindings" >&5
 $as_echo_n "checking whether to include the PHP bindings... " >&6; }
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $make_phpbindings" >&5
@@ -4346,7 +4350,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='getdata'
- VERSION='0.9.2.1'
+ VERSION='0.9.3'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4492,69 +4496,6 @@ fi
   test -n "$AWK" && break
 done
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$GREP"; then
-  ac_path_GREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in grep ggrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
-  # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'GREP' >> "conftest.nl"
-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_GREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_GREP="$ac_path_GREP"
-      ac_path_GREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_GREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_GREP"; then
-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
 $as_echo_n "checking for a sed that does not truncate output... " >&6; }
 if ${ac_cv_path_SED+:} false; then :
@@ -4863,7 +4804,7 @@ $as_echo "$this_is_msys" >&6; }
 if test "$this_is_msys" = "yes"; then
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Win32 MSYS shell" >&5
 $as_echo_n "checking for the Win32 MSYS shell... " >&6; }
-msys_root=`mount | ${GREP} 'on / ' | awk '{print $1}'`
+msys_root=`mount | ${AWK} '/on \/ / {print $1}'`
 msys_shell1="$msys_root`echo $SHELL | ${SED} -e 's/\//\\\\/g'`.exe"
 msys_shell=`echo "$msys_shell1" | ${SED} -e 's/\\\\/\\\\\\\\/g'`
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msys_shell1" >&5
@@ -4876,9 +4817,9 @@ _ACEOF
 fi
 
 
-DEFINE_GD_GETDATA_VERSION="#define GD_GETDATA_VERSION \"0.9.2\""
+DEFINE_GD_GETDATA_VERSION="#define GD_GETDATA_VERSION \"0.9.3\""
 
-DEFINE_GD_GETDATA_INT_VERSION="#define GD_GETDATA_INT_VERSION `${PRINTF} %i%02i 9 2`"
+DEFINE_GD_GETDATA_INT_VERSION="#define GD_GETDATA_INT_VERSION `${PRINTF} %i%02i 9 3`"
 
 echo
 echo "*** Checking host environment"
@@ -6158,6 +6099,69 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
 $as_echo_n "checking for egrep... " >&6; }
 if ${ac_cv_path_EGREP+:} false; then :
@@ -26172,7 +26176,7 @@ Usage: $0 [OPTIONS]
 Report bugs to <bug-libtool at gnu.org>."
 
 lt_cl_version="\
-GetData config.lt 0.9.2.1
+GetData config.lt 0.9.3
 configured by $0, generated by GNU Autoconf 2.69.
 
 Copyright (C) 2011 Free Software Foundation, Inc.
@@ -28353,7 +28357,9 @@ $as_echo_n "checking whether we are using the Intel Fortran-77 compiler... " >&6
 if ${gd_cv_f77_compiler_intel+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if $F77 -help 2>/dev/null | grep -q 'Intel.R. Fortran Compiler'; then
+
+if $F77 -help 2>/dev/null | \
+  grep 'Intel.R. Fortran Compiler' >/dev/null 2>/dev/null; then
 gd_cv_f77_compiler_intel=yes
 else
 gd_cv_f77_compiler_intel=no
@@ -29137,7 +29143,9 @@ $as_echo_n "checking whether we are using the Intel Fortran compiler... " >&6; }
 if ${gd_cv_fc_compiler_intel+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if $FC -help 2>/dev/null | grep -q 'Intel.R. Fortran Compiler'; then
+
+if $FC -help 2>/dev/null | \
+  grep 'Intel.R. Fortran Compiler' >/dev/null 2>/dev/null; then
 gd_cv_fc_compiler_intel=yes
 else
 gd_cv_fc_compiler_intel=no
@@ -31275,6 +31283,85 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test "x$make_f77bindings" = "xyes"; then
+  echo
+  echo "*** Configuring Fortran bindings"
+  echo
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+  if test "x${SED}" = "x"; then
+    make_f77bindings=no
+    make_f95bindings=no
+  fi
+fi
+
 if test "x$make_idlbindings" = "xyes"; then
   echo
   echo "*** Configuring interactive data language (IDL) bindings"
@@ -31290,6 +31377,7 @@ $as_echo "no" >&6; }
     make_idlbindings=no
   fi
 fi
+
 if test "x$make_idlbindings" = "xyes"; then
 
 idl_min_version=5.5
@@ -31326,14 +31414,17 @@ fi
 if test "x${have_idl}" != "xno"; then
 
 if test "x$user_idl" != "x"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $user_idl is an IDL interpreter version >= $idl_min_version" >&5
-$as_echo_n "checking whether $user_idl is an IDL interpreter version >= $idl_min_version... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $user_idl is an IDL interpreter version >=
+      $idl_min_version" >&5
+$as_echo_n "checking whether $user_idl is an IDL interpreter version >=
+      $idl_min_version... " >&6; }
 
 idl_version_ok="no"
 idl_header=`( echo | $user_idl 2>&1 )` #''
 IDL_VERSION="unknown"
-if echo $idl_header | grep -q "IDL Version"; then
-  IDL_VERSION=`echo $idl_header | grep Version | sed -e 's/IDL Version \([^ ]*\).*/\1/'` #'
+if echo $idl_header | grep "IDL Version" >/dev/null 2>/dev/null; then
+  IDL_VERSION=$(echo $idl_header | grep Version | \
+    sed -e 's/IDL Version \([^ ]*\).*/\1/')
 
 
 
@@ -31398,8 +31489,9 @@ do
 idl_version_ok="no"
 idl_header=`( echo | "$as_dir/$prog$exec_ext" 2>&1 )` #''
 IDL_VERSION="unknown"
-if echo $idl_header | grep -q "IDL Version"; then
-  IDL_VERSION=`echo $idl_header | grep Version | sed -e 's/IDL Version \([^ ]*\).*/\1/'` #'
+if echo $idl_header | grep "IDL Version" >/dev/null 2>/dev/null; then
+  IDL_VERSION=$(echo $idl_header | grep Version | \
+    sed -e 's/IDL Version \([^ ]*\).*/\1/')
 
 
 
@@ -31468,10 +31560,48 @@ $as_echo_n "checking $IDL version... " >&6; }
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $IDL_VERSION" >&5
 $as_echo "$IDL_VERSION" >&6; }
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the IDL prefix" >&5
+$as_echo_n "checking the IDL prefix... " >&6; }
+
+gd_idl_var=$(echo 'print,"@@@"+!DIR' | $IDL 2>/dev/null | \
+      grep '@@@' | sed -e 's/^@@@//')
+idl_prefix=${gd_idl_var}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${idl_prefix}" >&5
+$as_echo "${idl_prefix}" >&6; }
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $IDL DLM directory" >&5
 $as_echo_n "checking for $IDL DLM directory... " >&6; }
 if test "x${local_idl_dlm_path}" = "x"; then
-  idldir=`(echo 'print,"@@@"+!DLM_PATH' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@\([^:]*\)/\1/'`
+
+gd_idl_var=$(echo 'print,"@@@"+!DLM_PATH' | $IDL 2>/dev/null | \
+      grep '@@@' | sed -e 's/^@@@//')
+prefixed_idldir=$(echo $gd_idl_var | sed -e 's/^\([^:]*\)/\1/')
+
+
+  esc_idlprefix=$(echo ${idl_prefix} | sed -e 's/\//\\\//g')
+
+
+    config_eprefix=${exec_prefix}
+  if test "x${exec_prefix}" = "xNONE"; then
+    if test "x${prefix}" = "xNONE"; then
+      config_prefix=$ac_default_prefix
+    else
+      config_prefix=${prefix}
+    fi
+  else
+    config_prefix=${exec_prefix}
+  fi
+
+  if echo $prefixed_idldir | \
+    grep "^$config_prefix" >/dev/null 2>/dev/null; then
+    idldir=$(echo ${prefixed_idldir} | \
+        sed -e "s/^${esc_idlprefix}/\${idl_prefix}/")
+  else
+    idldir=$(echo ${prefixed_idldir} | \
+        sed -e "s/^${esc_idlprefix}/\${exec_prefix}/")
+  fi
 else
   idldir="$local_idl_dlm_path"
 fi
@@ -31481,15 +31611,22 @@ $as_echo "$idldir" >&6; }
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking IDL compiler flags" >&5
 $as_echo_n "checking IDL compiler flags... " >&6; }
-IDL_CFLAGS=`(echo 'print,"@@@"+!MAKE_DLL.CC' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@.*%X \(.*\) %C.*/\1/' | sed -e 's/\(.* \)-c\(.*\)/\1\2/' | sed -e 's/"//g'`
+
+gd_idl_var=$(echo 'print,"@@@"+!MAKE_DLL.CC' | $IDL 2>/dev/null | \
+      grep '@@@' | sed -e 's/^@@@//')
+IDL_CFLAGS=$(echo $gd_idl_var | sed -e 's/^.*%X \(.*\) %C.*/\1/; s/\(.* \)-c\(.*\)/\1\2/; s/"//g')
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $IDL_CFLAGS" >&5
 $as_echo "$IDL_CFLAGS" >&6; }
 
 
-
-IDL_LIBS=`(echo 'print,"@@@"+!MAKE_DLL.LD' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@[^ ]* \(.*\?\) -o.*/\1/' | sed -e 's/-m \?\w*//g'`
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking IDL linker flags" >&5
 $as_echo_n "checking IDL linker flags... " >&6; }
+
+gd_idl_var=$(echo 'print,"@@@"+!MAKE_DLL.LD' | $IDL 2>/dev/null | \
+      grep '@@@' | sed -e 's/^@@@//')
+IDL_LIBS=$(echo $gd_idl_var | sed -e 's/^[^ ]* \(.*\?\) -o.*/\1/; s/-m \?\w*//g')
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $IDL_LIBS" >&5
 $as_echo "$IDL_LIBS" >&6; }
 
@@ -31609,7 +31746,9 @@ $as_echo_n "checking if $MEX is a MATLAB mex compiler... " >&6; }
   mex_out=`$MEX 2>&1`
   mex_status=$?
   if test $mex_status -eq 1; then
-    if ! echo $mex_out | grep -q 'consult the MATLAB External Interfaces Guide'; then
+    if ! echo $mex_out | grep 'consult the MATLAB External Interfaces Guide' \
+      >/dev/null 2>/dev/null;
+    then
       MEX="not found";
     fi
   fi
@@ -31683,7 +31822,9 @@ fi
 $as_echo_n "checking $MATLAB version... " >&6; }
 
 matlab_int=$MATLAB
-MATLAB_VERSION=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r "fprintf(2, '@@@%s@@@\n', version); quit" 2>&1 >/dev/null | ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print $2 }'`
+MATLAB_VERSION=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r \
+  "fprintf(2, '@@@%s@@@\n', version); quit" 2>&1 >/dev/null | \
+  ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print $2 }'`
 
     if test "x$MATLAB_VERSION" = "x"; then
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
@@ -31727,7 +31868,9 @@ $as_echo "$matlabbasedir" >&6; }
 $as_echo_n "checking MEX extension... " >&6; }
 
 matlab_int=$MATLAB
-mexext=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r "fprintf(2, '@@@%s@@@\n', mexext); quit" 2>&1 >/dev/null | ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print $2 }'`
+mexext=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r \
+  "fprintf(2, '@@@%s@@@\n', mexext); quit" 2>&1 >/dev/null | \
+  ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print $2 }'`
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: .$mexext" >&5
 $as_echo ".$mexext" >&6; }
@@ -31753,15 +31896,81 @@ if test "x$make_perlbindings" = "xyes"; then
   echo
   echo "*** Configuring Perl bindings"
   echo
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+  if test "x${SED}" = "x"; then
+    make_perlbindings=no
+  else
 
 first_perl=5.8.0
-perl_prog_list="perl perl5 \
-perl5.14 perl5.12 perl5.10 perl5.8 \
-perl5.14.0 \
-perl5.12.3 perl5.12.2 perl5.12.1 perl5.12.0 \
-perl5.10.1 perl5.10.0 \
-perl5.8.9 perl5.8.8 perl5.8.7 perl5.8.6 perl5.8.5 perl5.8.4 perl5.8.3 \
-perl5.8.2 perl5.8.1 perl5.8.0"
+perl_prog_list="perl perl5"
 
 
 # Check whether --with-perl was given.
@@ -31993,12 +32202,17 @@ $as_echo_n "checking Perl module directory... " >&6; }
 
 perl_int=$PERL
 # 3=
-perldir=`$perl_int -V::vendorarchexp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+perlprefix=`$perl_int -V::vendorprefix: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+
+
+perl_int=$PERL
+# 3=
+prefixed_perldir=`$perl_int -V::vendorarchexp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
 
 
 perl_int=$PERL
 # 3=
-perlmandir=`$perl_int -V::vendorman3direxp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+prefixed_perlmandir=`$perl_int -V::vendorman3direxp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
 
     if test perldir = "UNKNOWN"; then
       perl_inst_type = "site";
@@ -32009,19 +32223,35 @@ perlmandir=`$perl_int -V::vendorman3direxp: | sed -e "s/'//g" | sed -e "s/ \t*$/
 
 perl_int=$PERL
 # 3=
-perldir=`$perl_int -V::sitearchexp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+perlprefix=`$perl_int -V::siteprefix: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
 
 
 perl_int=$PERL
 # 3=
-perlmandir=`$perl_int -V::siteman3direxp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+prefixed_perldir=`$perl_int -V::sitearchexp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+
 
-  elif test $perl_inst_type != "vendor"; then
+perl_int=$PERL
+# 3=
+prefixed_perlmandir=`$perl_int -V::siteman3direxp: | sed -e "s/'//g" | sed -e "s/ \t*$//"`
+
+  fi
+
+  if test $perl_inst_type = "local"; then
     perldir="${local_perl_path}"
     perlmandir="UNKNOWN"
+  elif test "x$SED" != "x"; then
+    esc_perlprefix=$(echo ${perlprefix} | ${SED} -e 's/\//\\\//g')
+    perldir=$(echo ${prefixed_perldir} | \
+        ${SED} -e "s/^${esc_perlprefix}/\${exec_prefix}/")
+    perlmandir=$(echo ${prefixed_perlmandir} | \
+        ${SED} -e "s/^${esc_perlprefix}/\${prefix}/")
+  else
+    perldir=${prefixed_perldir}
+    perlmandir=${prefixed_perlmandir}
   fi
 
-  if test $perlmandir = "UNKNOWN"; then
+  if test "x$perlmandir" = "xUNKNOWN"; then
     perlmandir="${mandir}/man3"
   fi
 
@@ -32038,15 +32268,17 @@ $as_echo "$perlmandir" >&6; }
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the section 3 manual page extension" >&5
 $as_echo_n "checking for the section 3 manual page extension... " >&6; }
-PERL_MAN3EXT=`$PERL -MExtUtils::MakeMaker::Config -e 'print "\n>>GD ", $Config{man3ext}, " GD<<";' | $AWK '/>>GD .* GD<</ { print $2 }'`
+PERL_MAN3EXT=`$PERL -MExtUtils::MakeMaker::Config -e 'print "\n>>GD ", \
+  $Config{man3ext}, " GD<<";' | $AWK '/>>GD .* GD<</ { print $2 }'`
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: .$PERL_MAN3EXT" >&5
 $as_echo ".$PERL_MAN3EXT" >&6; }
 
 
 fi
 
-  if test "x$have_perl" = "xno"; then
-    make_perlbindings=no
+    if test "x$have_perl" = "xno"; then
+      make_perlbindings=no
+    fi
   fi
 fi
 
@@ -32139,21 +32371,6 @@ test -n "$PHP_CONFIG" || PHP_CONFIG="not found"
 
 fi
 
-
-# Check whether --with-php-dir was given.
-if test "${with_php_dir+set}" = set; then :
-  withval=$with_php_dir;
-      if test "x${withval}" = "xno"; then
-        phpdir=UNKNOWN;
-      else
-        phpdir=${withval};
-      fi
-
-else
-  phpdir=UNKNOWN
-fi
-
-
 if test "x${have_php}" != "xno"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking PHP interpreter path" >&5
 $as_echo_n "checking PHP interpreter path... " >&6; }
@@ -32172,28 +32389,58 @@ $as_echo_n "checking PHP interpreter path... " >&6; }
 $as_echo "$PHP" >&6; }
 fi
 
+
+# Check whether --with-php-dir was given.
+if test "${with_php_dir+set}" = set; then :
+  withval=$with_php_dir;
+      if test "x${withval}" = "xno"; then
+        phpdir=UNKNOWN;
+      else
+        phpdir=${withval};
+      fi
+
+else
+  phpdir=UNKNOWN
+fi
+
+
 if test "x${have_php}" != "xno"; then
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking the PHP extension directory" >&5
 $as_echo_n "checking the PHP extension directory... " >&6; }
   if test "x${phpdir}" = "xUNKNOWN"; then
 
-  phpdir=`${PHP_CONFIG} --extension-dir`
+  phpprefix=`${PHP_CONFIG} --prefix`
 
-  if test "x${phpdir}" = "x"; then
-    phpdir="UNKNOWN";
+  if test "x${phpprefix}" = "x"; then
+    phpprefix="UNKNOWN";
     have_php="no";
-  elif test "x${phpdir}" = "xNONE"; then
+  elif test "x${phpprefix}" = "xNONE"; then
     have_php="no";
   fi
 
 
+
+  prefixed_phpdir=`${PHP_CONFIG} --extension-dir`
+
+  if test "x${prefixed_phpdir}" = "x"; then
+    prefixed_phpdir="UNKNOWN";
+    have_php="no";
+  elif test "x${prefixed_phpdir}" = "xNONE"; then
+    have_php="no";
+  fi
+
+
+    if test "x${prefixed_phpdir}" = "xUNKNOWN"; then
+      phpdir=${libdir}/php/extensions
+    elif test "x${SED}" != "x"; then
+      esc_phpprefix=$(echo ${phpprefix} | ${SED} -e 's/\//\\\//g')
+      phpdir=$(echo ${prefixed_phpdir} | \
+          ${SED} -e "s/^${esc_phpprefix}/\${exec_prefix}/")
+    fi
   fi
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $phpdir" >&5
 $as_echo "$phpdir" >&6; }
-  if test "x${phpdir}" = "xUNKNOWN"; then
-    have_php=no
-  fi
 
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking PHP CPPFLAGS" >&5
@@ -32234,20 +32481,22 @@ fi
 
 if test "x$make_pybindings" = "xyes"; then
   echo
-  echo "*** Configuring python bindings"
+  echo "*** Configuring Python bindings"
   echo
 
-last_python=2.7
-first_python=2.3
+first_python2=2.4
+last_python2=2.7
 
+first_python3=3.2
+last_python3=3.9
 if test "x$SEQ" == "xnot found"; then
   if test "x$JOT" == "xnot found"; then
-    python_prog_list="python python2"
+    python_prog_list="python python3 python2"
   else
-    python_prog_list="python python2     `$JOT -w 'python%.1f' - $last_python $first_python -0.1`" #'
+    python_prog_list="python     python3 `$JOT -w 'python%.1f' - $last_python3 $first_python3 -0.1`     python2 `$JOT -w 'python%.1f' - $last_python2 $first_python2 -0.1`" #'
   fi
 else
-  python_prog_list="python python2   `$SEQ -f 'python%.1f' $last_python -0.1 $first_python`" #'
+  python_prog_list="python   python3 `$SEQ -f 'python%.1f' $last_python3 -0.1 $first_python3`   python2 `$SEQ -f 'python%.1f' $last_python2 -0.1 $first_python2`" #'
 fi
 
 
@@ -32282,13 +32531,28 @@ fi
 if test "x${have_python}" != "xno"; then
 
 if test "x$user_python" != "x"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $user_python version >= $first_python" >&5
-$as_echo_n "checking whether $user_python version >= $first_python... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $user_python is new enough" >&5
+$as_echo_n "checking whether $user_python is new enough... " >&6; }
+
+
+if { echo "$as_me:$LINENO: $user_python -c 'import sys; sys.exit(int(sys.version[:1]) - 3)'
+  " >&5
+($user_python -c 'import sys; sys.exit(int(sys.version[:1]) - 3)'
+  ) >&5 2>&5
+ac_status=$?
+echo "$as_me:$LINENO: \$? = $ac_status" >&5
+(exit $ac_status); }; then :
+  have_python3=yes
+else
+  have_python3=no
+fi
+
+if test "$have_python3" = "no"; then
   prog="import sys
 # split strings by '.' and convert to numeric.  Append some zeros
 # because we need at least 4 digits for the hex conversion.
 # map returns an iterator in Python 3.0 and a list in 2.x
-minver = list(map(int, '$first_python'.split('.'))) + [0, 0, 0]
+minver = list(map(int, '$first_python2'.split('.'))) + [0, 0, 0]
 minverhex = 0
 # xrange is not present in Python 3.0 and range returns an iterator
 for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
@@ -32307,8 +32571,33 @@ $as_echo "no" >&6; }
   PYTHON="not found"
 fi
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python interpreter version >= $first_python" >&5
-$as_echo_n "checking for Python interpreter version >= $first_python... " >&6; }
+  prog="import sys
+# split strings by '.' and convert to numeric.  Append some zeros
+# because we need at least 4 digits for the hex conversion.
+# map returns an iterator in Python 3.0 and a list in 2.x
+minver = list(map(int, '$first_python3'.split('.'))) + [0, 0, 0]
+minverhex = 0
+# xrange is not present in Python 3.0 and range returns an iterator
+for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
+sys.exit(sys.hexversion < minverhex)"
+  if { echo "$as_me:$LINENO: $user_python -c "$prog"" >&5
+   ($user_python -c "$prog") >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  PYTHON=$user_python
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  PYTHON="not found"
+fi
+fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python interpreter version >= $first_python2" >&5
+$as_echo_n "checking for Python interpreter version >= $first_python2... " >&6; }
   PYTHON="not found"
   for py in $python_prog_list; do
   as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -32318,11 +32607,26 @@ do
   test -z "$as_dir" && as_dir=.
     for exec_ext in '' $ac_executable_extensions; do
     if as_fn_executable_p "$as_dir/$py$exec_ext"; then
-      prog="import sys
+
+
+if { echo "$as_me:$LINENO: "$as_dir/$py$exec_ext" -c 'import sys; sys.exit(int(sys.version[:1]) - 3)'
+  " >&5
+("$as_dir/$py$exec_ext" -c 'import sys; sys.exit(int(sys.version[:1]) - 3)'
+  ) >&5 2>&5
+ac_status=$?
+echo "$as_me:$LINENO: \$? = $ac_status" >&5
+(exit $ac_status); }; then :
+  have_python3=yes
+else
+  have_python3=no
+fi
+
+if test "$have_python3" = "no"; then
+  prog="import sys
 # split strings by '.' and convert to numeric.  Append some zeros
 # because we need at least 4 digits for the hex conversion.
 # map returns an iterator in Python 3.0 and a list in 2.x
-minver = list(map(int, '$first_python'.split('.'))) + [0, 0, 0]
+minver = list(map(int, '$first_python2'.split('.'))) + [0, 0, 0]
 minverhex = 0
 # xrange is not present in Python 3.0 and range returns an iterator
 for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
@@ -32334,6 +32638,25 @@ sys.exit(sys.hexversion < minverhex)"
    (exit $ac_status); }; then :
    PYTHON="$as_dir/$py$exec_ext"; break 3
 fi
+else
+  prog="import sys
+# split strings by '.' and convert to numeric.  Append some zeros
+# because we need at least 4 digits for the hex conversion.
+# map returns an iterator in Python 3.0 and a list in 2.x
+minver = list(map(int, '$first_python3'.split('.'))) + [0, 0, 0]
+minverhex = 0
+# xrange is not present in Python 3.0 and range returns an iterator
+for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
+sys.exit(sys.hexversion < minverhex)"
+  if { echo "$as_me:$LINENO: "$as_dir/$py$exec_ext" -c "$prog"" >&5
+   ("$as_dir/$py$exec_ext" -c "$prog") >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); }; then :
+   PYTHON="$as_dir/$py$exec_ext"; break 3
+fi
+fi
+
     fi
   done
   done
@@ -32353,53 +32676,192 @@ fi
 fi
 
 if test "x${have_python}" != "xno"; then
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we're using a Python3 interpreter" >&5
+$as_echo_n "checking if we're using a Python3 interpreter... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_python3" >&5
+$as_echo "$have_python3" >&6; }
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking $PYTHON version" >&5
 $as_echo_n "checking $PYTHON version... " >&6; }
-PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[:3]"`
+PYTHON_VERSION=`$PYTHON -c "import sys; print (sys.version[:3])"`
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_VERSION" >&5
 $as_echo "$PYTHON_VERSION" >&6; }
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python includes" >&5
-$as_echo_n "checking Python includes... " >&6; }
-if test -x $PYTHON-config; then
-  PYTHON_CPPFLAGS=`$PYTHON-config --includes 2>/dev/null`
-else
-  python_prefix=`$PYTHON -c "import sys; print sys.prefix"`
-  python_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
-  PYTHON_CPPFLAGS="-I${python_prefix}/include/python${PYTHON_VERSION} -I${python_exec_prefix}/include/python${PYTHON_VERSION}"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python ABI version" >&5
+$as_echo_n "checking Python ABI version... " >&6; }
+
+  PYTHON_LDVERSION=$(${PYTHON} - <<EOF 2>/dev/null
+try:
+  import sysconfig
+except ImportError:
+  from distutils import sysconfig
+
+print (sysconfig.get_config_var("LDVERSION"))
+EOF
+)
+
+  if test "x${PYTHON_LDVERSION}" = "x"; then PYTHON_LDVERSION=None; fi
+
+if test "${PYTHON_LDVERSION}" = "None"; then
+  PYTHON_LDVERSION=${PYTHON_VERSION}
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_LDVERSION" >&5
+$as_echo "$PYTHON_LDVERSION" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python CPPFLAGS" >&5
+$as_echo_n "checking Python CPPFLAGS... " >&6; }
+python_prefix=`$PYTHON -c "import sys; print (sys.prefix)"`
+python_exec_prefix=`$PYTHON -c "import sys; print (sys.exec_prefix)"`
+PYTHON_CPPFLAGS="-I${python_prefix}/include/python${PYTHON_LDVERSION}"
+if test "x${python_prefix}" != "x${python_exec_prefix}"; then
+  PYTHON_CPPFLAGS="${PYTHON_CPPFLAGS} -I${python_exec_prefix}/include/python${PYTHON_LDVERSION}"
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_CPPFLAGS" >&5
 $as_echo "$PYTHON_CPPFLAGS" >&6; }
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python LDFLAGS" >&5
+$as_echo_n "checking Python LDFLAGS... " >&6; }
+
+  PYTHON_LIBDIR=$(${PYTHON} - <<EOF 2>/dev/null
+try:
+  import sysconfig
+except ImportError:
+  from distutils import sysconfig
+
+print (sysconfig.get_config_var("LIBDIR"))
+EOF
+)
+
+  if test "x${PYTHON_LIBDIR}" = "x"; then PYTHON_LIBDIR=None; fi
+
+PYTHON_LDFLAGS="-L${PYTHON_LIBDIR} -lpython${PYTHON_LDVERSION}"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_LDFLAGS" >&5
+$as_echo "$PYTHON_LDFLAGS" >&6; }
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python platform name" >&5
 $as_echo_n "checking Python platform name... " >&6; }
-PYTHON_PLATFORM=`$PYTHON -c "from distutils import util; print util.get_platform()"`
+PYTHON_PLATFORM=`$PYTHON -c \
+  "from distutils import util; print (util.get_platform())"`
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_PLATFORM" >&5
 $as_echo "$PYTHON_PLATFORM" >&6; }
 
 
-pyexec_prefix=$exec_prefix
-test "x$pyexec_prefix" = xNONE && pyexec_prefix=$prefix
-test "x$pyexec_prefix" = xNONE && pyexec_prefix=$ac_default_prefix
-
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python extension module directory" >&5
 $as_echo_n "checking Python extension module directory... " >&6; }
 if test "x${local_python_modpath}" = "x"; then
-  pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='${pyexec_prefix}')" 2>/dev/null || echo "${pyexec_prefix}/lib/python${PYTHON_VERSION}/site-packages"`
+  pythondir=$(${PYTHON} - <<EOF 2>/dev/null
+import sys
+if sys.version[:1] == '3':
+  import sysconfig
+  print (sysconfig.get_path('platlib', vars={'platbase': '\${exec_prefix}'}))
+else:
+  from distutils import sysconfig
+  print (sysconfig.get_python_lib(1,0,prefix='\${exec_prefix}'))
+EOF
+)
+  if test "x${pythondir}" = "xNone" -o "x${pythondir}" = "x"; then
+    pythondir='\${exec_prefix}/lib/python${PYTHON_LDVERSION}/site-packages'
+  fi
 else
   pythondir=$local_python_modpath
 fi
-
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pythondir" >&5
 $as_echo "$pythondir" >&6; }
 
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python object suffix" >&5
+$as_echo_n "checking Python object suffix... " >&6; }
+
+  PYTHON_OBJECT_SUFFIX=$(${PYTHON} - <<EOF 2>/dev/null
+try:
+  import sysconfig
+except ImportError:
+  from distutils import sysconfig
+
+print (sysconfig.get_config_var("SO"))
+EOF
+)
+
+  if test "x${PYTHON_OBJECT_SUFFIX}" = "x"; then PYTHON_OBJECT_SUFFIX=None; fi
+
+if test "x${PYTHON_OBJECT_SUFFIX}" = "xNone"; then
+
+  PYTHON_OBJECT_SUFFIX=$(${PYTHON} - <<EOF 2>/dev/null
+try:
+  import sysconfig
+except ImportError:
+  from distutils import sysconfig
+
+print (sysconfig.get_config_var("EXT_SUFFIX"))
+EOF
+)
+
+  if test "x${PYTHON_OBJECT_SUFFIX}" = "x"; then PYTHON_OBJECT_SUFFIX=None; fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_OBJECT_SUFFIX" >&5
+$as_echo "$PYTHON_OBJECT_SUFFIX" >&6; }
+
+
+if test "$have_python3" = "no"; then
+saved_CPPFLAGS=${CPPFLAGS}
+CPPFLAGS="${PYTHON_CPPFLAGS} ${CPPFLAGS}"
+ac_fn_c_check_decl "$LINENO" "Py_USING_UNICODE" "ac_cv_have_decl_Py_USING_UNICODE" "
+#include <Python.h>
+
+"
+if test "x$ac_cv_have_decl_Py_USING_UNICODE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PY_USING_UNICODE $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+  have_pyunicode=yes
+else
+  have_pyunicode="no (required)"
+fi
+
+CPPFLAGS=${saved_CPPFLAGS}
+else
+have_pyunicode=yes
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Unicode support in Python" >&5
+$as_echo_n "checking for Unicode support in Python... " >&6; }
+if test "${have_pyunicode}" != "yes"; then
+  have_python=no
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_pyunicode" >&5
+$as_echo "$have_pyunicode" >&6; }
+
 fi
 
-  have_numpy="no (required for python bindings)"
+  have_numpy="no (required for Python bindings)"
   if test "x$have_python" = "xno"; then
     make_pybindings="no"
   else
+        saved_LDFLAGS=${LDFLAGS}
+    LDFLAGS="${PYTHON_LDFLAGS} ${LDFLAGS}"
+    for ac_func in PyCapsule_New PyErr_NewExceptionWithDoc
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+    LDFLAGS=${saved_LDFLAGS}
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NumPy" >&5
 $as_echo_n "checking for NumPy... " >&6; }
     cat > conftest.py << EOF
@@ -32416,9 +32878,9 @@ EOF
 $as_echo "$have_numpy" >&6; }
   fi
   if test "x$have_numpy" = "xyes"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking NumPy includes" >&5
-$as_echo_n "checking NumPy includes... " >&6; }
-    NUMPY_CPPFLAGS=-I`$PYTHON -c "import numpy; print numpy.get_include()"`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking NumPy CPPFLAGS" >&5
+$as_echo_n "checking NumPy CPPFLAGS... " >&6; }
+    NUMPY_CPPFLAGS=-I`$PYTHON -c "import numpy; print (numpy.get_include())"`
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NUMPY_CPPFLAGS" >&5
 $as_echo "$NUMPY_CPPFLAGS" >&6; }
 
@@ -34164,8 +34626,8 @@ fi
 cat <<EOF > conftest.sh
 prefix=$prefix
 test "x$prefix" = xNONE && prefix=$ac_default_prefix
-test "x$exec_prefix" = xNONE && exec_prefix=\$prefix
 exec_prefix=$exec_prefix
+test "x$exec_prefix" = xNONE && exec_prefix=\$prefix
 datarootdir=$datarootdir
 PACKAGE_TARNAME=$PACKAGE_TARNAME
 echo $docdir
@@ -34311,6 +34773,14 @@ else
   MAKE_PYBINDINGS_FALSE=
 fi
 
+ if test "x$ac_cv_func_PyCapsule_New" = "xyes"; then
+  MAKE_PYGETDATA_CAPI_TRUE=
+  MAKE_PYGETDATA_CAPI_FALSE='#'
+else
+  MAKE_PYGETDATA_CAPI_TRUE='#'
+  MAKE_PYGETDATA_CAPI_FALSE=
+fi
+
  if test "x$make_idlbindings" = "xyes"; then
   MAKE_IDLBINDINGS_TRUE=
   MAKE_IDLBINDINGS_FALSE='#'
@@ -34418,6 +34888,8 @@ fi
 
 LDFLAGS="${LDFLAGS}${NO_UNDEFINED}"
 
+
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -34624,6 +35096,10 @@ if test -z "${MAKE_PYBINDINGS_TRUE}" && test -z "${MAKE_PYBINDINGS_FALSE}"; then
   as_fn_error $? "conditional \"MAKE_PYBINDINGS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${MAKE_PYGETDATA_CAPI_TRUE}" && test -z "${MAKE_PYGETDATA_CAPI_FALSE}"; then
+  as_fn_error $? "conditional \"MAKE_PYGETDATA_CAPI\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${MAKE_IDLBINDINGS_TRUE}" && test -z "${MAKE_IDLBINDINGS_FALSE}"; then
   as_fn_error $? "conditional \"MAKE_IDLBINDINGS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -35073,7 +35549,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by GetData $as_me 0.9.2.1, which was
+This file was extended by GetData $as_me 0.9.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -35140,7 +35616,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-GetData config.status 0.9.2.1
+GetData config.status 0.9.3
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index fa1e97c..0d8c055 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,7 +81,7 @@ AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
 
 dnl Legacy API
-AC_ARG_ENABLE(legacy-api, AS_HELP_STRING([--enaable-legacy-api],
+AC_ARG_ENABLE(legacy-api, AS_HELP_STRING([--enable-legacy-api],
               [include the legacy API wrapper in the library]), dnl'
               [
                case "${enableval}" in
@@ -271,16 +271,6 @@ AC_ARG_ENABLE(perl, AS_HELP_STRING([--disable-perl],
 AC_MSG_CHECKING([whether to include the Perl bindings])
 AC_MSG_RESULT([$make_perlbindings])
 
-dnl PHP bindings
-AC_ARG_ENABLE(php, AS_HELP_STRING([--disable-php],
-              [don't build the PHP bindings]),dnl'
-              [
-               case "${enableval}" in
-                 no) make_phpbindings="no" ;;
-                 *) make_phpbindings="yes" ;;
-               esac
-              ])
-
 dnl Python bindings
 AC_ARG_ENABLE(python, AS_HELP_STRING([--disable-python],
               [don't build the Python bindings (pygetdata)]),dnl'
@@ -294,6 +284,16 @@ AC_ARG_ENABLE(python, AS_HELP_STRING([--disable-python],
 AC_MSG_CHECKING([whether to include the Python bindings])
 AC_MSG_RESULT([$make_pybindings])
 
+dnl PHP bindings
+AC_ARG_ENABLE(php, AS_HELP_STRING([--disable-php],
+              [don't build the PHP bindings]),dnl'
+              [
+               case "${enableval}" in
+                 no) make_phpbindings="no" ;;
+                 *) make_phpbindings="yes" ;;
+               esac
+              ])
+
 AC_MSG_CHECKING([whether to include the PHP bindings])
 AC_MSG_RESULT([$make_phpbindings])
 
@@ -352,7 +352,6 @@ echo
 AM_INIT_AUTOMAKE
 AC_PROG_LN_S
 AC_PROG_AWK
-AC_PROG_GREP
 AC_PROG_SED
 
 AC_ARG_VAR([DATE], \
@@ -872,6 +871,18 @@ AC_CHECK_DECLS([get_unaligned, put_unaligned],,,
 #endif
 ])
 
+dnl The Fortran build needs a non-truncating sed
+if test "x$make_f77bindings" = "xyes"; then
+  echo
+  echo "*** Configuring Fortran bindings"
+  echo
+  AC_PROG_SED
+  if test "x${SED}" = "x"; then
+    make_f77bindings=no
+    make_f95bindings=no
+  fi
+fi
+
 dnl idl
 if test "x$make_idlbindings" = "xyes"; then
   echo
@@ -885,6 +896,7 @@ if test "x$make_idlbindings" = "xyes"; then
     make_idlbindings=no
   fi
 fi
+
 if test "x$make_idlbindings" = "xyes"; then
   GD_IDL([5.5])
   if test "x$have_idl" = "xno"; then
@@ -908,9 +920,14 @@ if test "x$make_perlbindings" = "xyes"; then
   echo
   echo "*** Configuring Perl bindings"
   echo
-  GD_PERL
-  if test "x$have_perl" = "xno"; then
+  AC_PROG_SED
+  if test "x${SED}" = "x"; then
     make_perlbindings=no
+  else
+    GD_PERL
+    if test "x$have_perl" = "xno"; then
+      make_perlbindings=no
+    fi
   fi
 fi
 
@@ -937,13 +954,19 @@ fi
 dnl python
 if test "x$make_pybindings" = "xyes"; then
   echo
-  echo "*** Configuring python bindings"
+  echo "*** Configuring Python bindings"
   echo
-  GD_PYTHON([2.3])
-  have_numpy="no (required for python bindings)"
+  GD_PYTHON([2.4],[3.2])
+  have_numpy="no (required for Python bindings)"
   if test "x$have_python" = "xno"; then
     make_pybindings="no"
   else
+    dnl Check for optional components
+    saved_LDFLAGS=${LDFLAGS}
+    LDFLAGS="${PYTHON_LDFLAGS} ${LDFLAGS}"
+    AC_CHECK_FUNCS([PyCapsule_New PyErr_NewExceptionWithDoc])
+    LDFLAGS=${saved_LDFLAGS}
+
     AC_MSG_CHECKING([for NumPy])
     cat > conftest.py << EOF
 import sys
@@ -958,8 +981,8 @@ EOF
     AC_MSG_RESULT([$have_numpy])
   fi
   if test "x$have_numpy" = "xyes"; then
-    AC_MSG_CHECKING([NumPy includes])
-    NUMPY_CPPFLAGS=-I`$PYTHON -c "import numpy; print numpy.get_include()"`
+    AC_MSG_CHECKING([NumPy CPPFLAGS])
+    NUMPY_CPPFLAGS=-I`$PYTHON -c "import numpy; print (numpy.get_include())"`
     AC_MSG_RESULT([$NUMPY_CPPFLAGS])
 
     saved_cppflags=$CPPFLAGS
@@ -1076,8 +1099,8 @@ dnl Calculate absolute docdir
 cat <<EOF > conftest.sh
 prefix=$prefix
 test "x$prefix" = xNONE && prefix=$ac_default_prefix
-test "x$exec_prefix" = xNONE && exec_prefix=\$prefix
 exec_prefix=$exec_prefix
+test "x$exec_prefix" = xNONE && exec_prefix=\$prefix
 datarootdir=$datarootdir
 PACKAGE_TARNAME=$PACKAGE_TARNAME
 echo $docdir
@@ -1134,6 +1157,8 @@ AM_CONDITIONAL(MAKE_CXXBINDINGS, [test "x$make_cxxbindings" = "xyes"])
 AM_CONDITIONAL(MAKE_F77BINDINGS, [test "x$make_f77bindings" != "xno"])
 AM_CONDITIONAL(MAKE_F95BINDINGS, [test "x$make_f95bindings" = "xyes"])
 AM_CONDITIONAL(MAKE_PYBINDINGS, [test "x$make_pybindings" = "xyes"])
+AM_CONDITIONAL(MAKE_PYGETDATA_CAPI,
+               [test "x$ac_cv_func_PyCapsule_New" = "xyes"])
 AM_CONDITIONAL(MAKE_IDLBINDINGS, [test "x$make_idlbindings" = "xyes"])
 AM_CONDITIONAL(MAKE_PERLBINDINGS, [test "x$make_perlbindings" = "xyes"])
 AM_CONDITIONAL(MAKE_MATLABBINDINGS, [test "x$make_matlabbindings" = "xyes"])
@@ -1151,6 +1176,8 @@ AM_CONDITIONAL(GD_EXTERNAL, [false])
 dnl we do this here to avoid screwing up other tests
 LDFLAGS="${LDFLAGS}${NO_UNDEFINED}"
 
+AH_BOTTOM([#include "gd_extra_config.h"])
+
 AC_OUTPUT
 
 dnl Handy summary
diff --git a/doc/Makefile.in b/doc/Makefile.in
index f08ce31..fee1d53 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -298,6 +298,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -347,6 +348,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/m4/compiler.m4 b/m4/compiler.m4
index f6031c8..db263e0 100644
--- a/m4/compiler.m4
+++ b/m4/compiler.m4
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2008-2010, 2012, 2013, 2015 D. V. Wiebe
+dnl Copyright (C) 2008-2010, 2012, 2013, 2015, 2016 D. V. Wiebe
 dnl
 dnl llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
 dnl
@@ -70,7 +70,9 @@ dnl Check whether the compiler for Fortran is Intel.
 AC_DEFUN([GD_LANG_F77_COMPILER_INTEL],
 [AC_CACHE_CHECK([whether we are using the Intel Fortran-77 compiler],
 [gd_cv_f77_compiler_intel],
-[if $F77 -help 2>/dev/null | grep -q 'Intel.R. Fortran Compiler'; then
+[
+if $F77 -help 2>/dev/null | \
+  grep 'Intel.R. Fortran Compiler' >/dev/null 2>/dev/null; then
 gd_cv_f77_compiler_intel=yes
 else
 gd_cv_f77_compiler_intel=no
@@ -83,7 +85,9 @@ dnl Check whether the compiler for free-form Fortran is Intel.
 AC_DEFUN([GD_LANG_FC_COMPILER_INTEL],
 [AC_CACHE_CHECK([whether we are using the Intel Fortran compiler],
 [gd_cv_fc_compiler_intel],
-[if $FC -help 2>/dev/null | grep -q 'Intel.R. Fortran Compiler'; then
+[
+if $FC -help 2>/dev/null | \
+  grep 'Intel.R. Fortran Compiler' >/dev/null 2>/dev/null; then
 gd_cv_fc_compiler_intel=yes
 else
 gd_cv_fc_compiler_intel=no
diff --git a/m4/encoding.m4 b/m4/encoding.m4
index 3185939..2fea98a 100644
--- a/m4/encoding.m4
+++ b/m4/encoding.m4
@@ -37,7 +37,8 @@ AC_ARG_WITH([lib$2], AS_HELP_STRING([--with-lib$2=PREFIX],
              esac
              ], [ use_[]gd_encoding="yes"; gd_encoding[]_prefix=; ])
 m4_divert_once([HELP_WITH], AS_HELP_STRING([--without-lib$2],
-            [disable encodings supported by lib$2, even if the library is present]))
+            [disable encodings supported by lib$2, even if the library is ]
+            [present]))
 
 echo
 echo "*** Configuring gd_encoding support"
@@ -88,7 +89,8 @@ if test "x$have_this_header" = "xyes" -a "x$have_this_lib" = "xyes"; then
     AS_TR_CPP(gd_encoding[_LIBS])="-l$2"
     AS_TR_CPP(gd_encoding[_SEARCHPATH])="$gd_encoding[]_prefix/bin:$PATH"
   fi
-  AC_DEFINE(AS_TR_CPP([USE_]gd_encoding), [], [ Define to enable ]gd_encoding[ support ])
+  AC_DEFINE(AS_TR_CPP([USE_]gd_encoding), [], [ Define to ]
+  [enable ]gd_encoding[ support ])
 else
   use_[]gd_encoding="no";
   AS_TR_CPP(gd_encoding[_SEARCHPATH])="$PATH"
@@ -99,7 +101,8 @@ AC_SUBST(AS_TR_CPP(gd_encoding[_LIBS]))
 
 dnl executables needed for tests
 m4_define([gd_progname], regexp([$5 ], [^\([^ ]*\) ], [\1]))
-AC_PATH_PROGS([path_]gd_progname, [$5], [not found], [$AS_TR_CPP(gd_encoding[_SEARCHPATH])])
+AC_PATH_PROGS([path_]gd_progname, [$5], [not found],
+  [$AS_TR_CPP(gd_encoding[_SEARCHPATH])])
 
 if test "x$path_[]gd_progname" != "xnot found"; then
   AC_DEFINE_UNQUOTED(AS_TR_CPP(gd_progname), ["$path_]gd_progname["],
@@ -108,18 +111,21 @@ fi
 
 ifelse(`x$6', `x',,[
 m4_define([gd_unprogname], regexp([$6 ], [^\([^ ]*\) ], [\1]))
-AC_PATH_PROGS([path_]gd_unprogname, [$6], [not found], [$AS_TR_CPP(gd_encoding[_SEARCHPATH])])
+AC_PATH_PROGS([path_]gd_unprogname, [$6], [not found],
+  [$AS_TR_CPP(gd_encoding[_SEARCHPATH])])
 
 if test "x$path_[]gd_unprogname" != "xnot found"; then
   AC_DEFINE_UNQUOTED(AS_TR_CPP(gd_unprogname), ["$path_]gd_unprogname["],
-                     [ Define to the full path to the `]gd_unprogname[' binary ])
+    [ Define to the full path to the `]gd_unprogname[' binary ])
 fi
 ])
-AM_CONDITIONAL(AS_TR_CPP([USE_]gd_encoding), [test "x$use_]gd_encoding[" = "xyes"])
+AM_CONDITIONAL(AS_TR_CPP([USE_]gd_encoding),
+    [test "x$use_]gd_encoding[" = "xyes"])
 
 if test "x$path_[]gd_progname" != "xnot found" -a \
   "x$path_[]gd_unprogname" != "xnot found"; then
-  AC_DEFINE(AS_TR_CPP([TEST_]gd_encoding), [], [ Define to enable ]gd_encoding[ tests ])
+  AC_DEFINE(AS_TR_CPP([TEST_]gd_encoding), [],
+      [ Define to enable ]gd_encoding[ tests ])
 fi
 
 dnl add to summary and private lib list
diff --git a/m4/idl.m4 b/m4/idl.m4
index 115e0c1..d90075f 100644
--- a/m4/idl.m4
+++ b/m4/idl.m4
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2009, 2011, 2012, 2013 D. V. Wiebe
+dnl Copyright (C) 2009, 2011, 2012, 2013, 2016 D. V. Wiebe
 dnl
 dnl llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
 dnl
@@ -18,6 +18,18 @@ dnl You should have received a copy of the GNU Lesser General Public License
 dnl along with GetData; if not, write to the Free Software Foundation, Inc.,
 dnl 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
+dnl GD_IDL_VAR(NAME, IDLVAR, [SEDEXPR])
+dnl ---------------------------------------------------------
+dnl Assign the value of IDL variable IDLVAR to the variable NAME after
+dnl optionally processing it with the sed script SEDEXPR
+AC_DEFUN([GD_IDL_VAR],
+[
+gd_idl_var=$(echo 'print,"@@@"+$2' | $IDL 2>/dev/null | \
+      grep '@@@' | sed -e 's/^@@@//')
+ifelse(`$#', `2', [$1=${gd_idl_var}],
+  [$1=$(echo $gd_idl_var | sed -e '$3')])
+])
+
 dnl GD_IDL_CHECK_VERSION
 dnl ---------------------------------------------------------------
 dnl Define IDL_VERSION to the version of the idl interpreter
@@ -26,8 +38,9 @@ AC_DEFUN([GD_IDL_CHECK_VERSION],
 idl_version_ok="no"
 idl_header=`( echo | $1 2>&1 )` #''
 IDL_VERSION="unknown"
-if echo $idl_header | grep -q "IDL Version"; then
-  IDL_VERSION=`echo $idl_header | grep Version | sed -e 's/IDL Version \(@<:@^ @:>@*\).*/\1/'` #'
+if echo $idl_header | grep "IDL Version" >/dev/null 2>/dev/null; then
+  IDL_VERSION=$(echo $idl_header | grep Version | \
+    sed -e 's/IDL Version \(@<:@^ @:>@*\).*/\1/')
   AX_COMPARE_VERSION([$IDL_VERSION],[ge],[$2],[idl_version_ok="yes"])
 fi
 if test "x$idl_version_ok" = "xyes"; then
@@ -69,7 +82,8 @@ if test "x${have_idl}" != "xno"; then
 
 dnl try to find a sufficiently new IDL.
 if test "x$user_idl" != "x"; then
-  AC_MSG_CHECKING([whether $user_idl is an IDL interpreter version >= $idl_min_version])
+  AC_MSG_CHECKING([whether $user_idl is an IDL interpreter version >= ]
+      [$idl_min_version])
   GD_IDL_CHECK_VERSION([$user_idl], [$idl_min_version],
   [AC_MSG_RESULT([yes])
   IDL=$user_idl],
@@ -103,10 +117,43 @@ dnl idl version
 AC_MSG_CHECKING([$IDL version])
 AC_MSG_RESULT([$IDL_VERSION])
 
+dnl IDL prefix
+AC_MSG_CHECKING([the IDL prefix])
+GD_IDL_VAR([idl_prefix], [!DIR])
+AC_MSG_RESULT([${idl_prefix}])
+AC_SUBST([idl_prefix])
+
 dnl calculate idl CPPFLAGS and LIBS
 AC_MSG_CHECKING([for $IDL DLM directory])
 if test "x${local_idl_dlm_path}" = "x"; then
-  idldir=`(echo 'print,"@@@"+!DLM_PATH' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@\(@<:@^:@:>@*\)/\1/'`
+  GD_IDL_VAR([prefixed_idldir], [!DLM_PATH], [s/^\(@<:@^:@:>@*\)/\1/])
+
+  esc_idlprefix=$(echo ${idl_prefix} | sed -e 's/\//\\\//g')
+
+  dnl if ${idl_prefix} isn't in contained in ${exec_prefix}, then replace
+  dnl idl_prefix with exec_prefix in the DLM path, so that IDL is installed
+  dnl under ${exec_prefix}.
+
+  dnl We really should do this at build time, I suppose...
+  config_eprefix=${exec_prefix}
+  if test "x${exec_prefix}" = "xNONE"; then
+    if test "x${prefix}" = "xNONE"; then
+      config_prefix=$ac_default_prefix
+    else
+      config_prefix=${prefix}
+    fi
+  else
+    config_prefix=${exec_prefix}
+  fi
+
+  if echo $prefixed_idldir | \
+    grep "^$config_prefix" >/dev/null 2>/dev/null; then
+    idldir=$(echo ${prefixed_idldir} | \
+        sed -e "s/^${esc_idlprefix}/\${idl_prefix}/")
+  else
+    idldir=$(echo ${prefixed_idldir} | \
+        sed -e "s/^${esc_idlprefix}/\${exec_prefix}/")
+  fi
 else
   idldir="$local_idl_dlm_path"
 fi
@@ -114,13 +161,14 @@ AC_MSG_RESULT([$idldir])
 AC_SUBST([idldir])
 
 AC_MSG_CHECKING([IDL compiler flags])
-IDL_CFLAGS=`(echo 'print,"@@@"+!MAKE_DLL.CC' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@.*%X \(.*\) %C.*/\1/' | sed -e 's/\(.* \)-c\(.*\)/\1\2/' | sed -e 's/"//g'`
+GD_IDL_VAR([IDL_CFLAGS],[!MAKE_DLL.CC],
+    [s/^.*%X \(.*\) %C.*/\1/; s/\(.* \)-c\(.*\)/\1\2/; s/"//g])
 AC_MSG_RESULT([$IDL_CFLAGS])
 AC_SUBST([IDL_CFLAGS])
 
-AC_SUBST([IDL_CFLAGS])
-IDL_LIBS=`(echo 'print,"@@@"+!MAKE_DLL.LD' | $IDL 2>&1) | $GREP '@@@' | sed -e 's/@@@@<:@^ @:>@* \(.*\?\) -o.*/\1/' | sed -e 's/-m \?[\w]*//g'`
 AC_MSG_CHECKING([IDL linker flags])
+GD_IDL_VAR([IDL_LIBS],[!MAKE_DLL.LD],
+    [s/^@<:@^ @:>@* \(.*\?\) -o.*/\1/; s/-m \?[\w]*//g])
 AC_MSG_RESULT([$IDL_LIBS])
 AC_SUBST([IDL_LIBS])
 
diff --git a/m4/matlab.m4 b/m4/matlab.m4
index c80ebbc..84729c4 100644
--- a/m4/matlab.m4
+++ b/m4/matlab.m4
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2013, 2014 D. V. Wiebe
+dnl Copyright (C) 2013, 2014, 2016 D. V. Wiebe
 dnl
 dnl llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
 dnl
@@ -43,12 +43,15 @@ else
   AC_PATH_PROG([MEX], [mex], [not found])
 fi
 
+dnl TexLive contains a /usr/bin/mex
 if test "x$MEX" != "xnot found"; then
   AC_MSG_CHECKING([if $MEX is a MATLAB mex compiler])
   mex_out=`$MEX 2>&1`
   mex_status=$?
   if test $mex_status -eq 1; then
-    if ! echo $mex_out | grep -q 'consult the MATLAB External Interfaces Guide'; then
+    if ! echo $mex_out | grep 'consult the MATLAB External Interfaces Guide' \
+      >/dev/null 2>/dev/null;
+    then
       MEX="not found";
     fi
   fi
@@ -83,7 +86,9 @@ dnl variable
 AC_DEFUN([GD_MATLAB_EVAL],
 [
 ifelse(`$#', `2', [matlab_int=$MATLAB], [matlab_int=$3])
-$1=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r "fprintf(2, '@@@%s@@@\n', $2); quit" 2>&1 >/dev/null | ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print @S|@2 }'`
+$1=`$matlab_int -nodisplay -nosplash -nojvm -nodesktop -r \
+  "fprintf(2, '@@@%s@@@\n', $2); quit" 2>&1 >/dev/null | \
+  ${AWK} 'BEGIN { FS="@@@" } /^@@@/ { print @S|@2 }'`
 ])
 
 dnl GD_MATLAB
diff --git a/m4/perl.m4 b/m4/perl.m4
index 32e624b..7f6d681 100644
--- a/m4/perl.m4
+++ b/m4/perl.m4
@@ -53,7 +53,8 @@ dnl ExtUtils::MakeMaker
 AC_DEFUN([GD_PERL_MAN3EXT],
 [
 AC_MSG_CHECKING([for the section 3 manual page extension])
-PERL_MAN3EXT=`$PERL -MExtUtils::MakeMaker::Config -e 'print "\n>>GD ", @S|@Config{man3ext}, " GD<<";' | $AWK '/>>GD .* GD<</ { print @S|@2 }'`
+PERL_MAN3EXT=`$PERL -MExtUtils::MakeMaker::Config -e 'print "\n>>GD ", \
+  @S|@Config{man3ext}, " GD<<";' | $AWK '/>>GD .* GD<</ { print @S|@2 }'`
 AC_MSG_RESULT([.$PERL_MAN3EXT])
 AC_SUBST([PERL_MAN3EXT])
 ])
@@ -78,13 +79,7 @@ dnl Look for perl5.  Then determine whether we can build XSUBs.
 AC_DEFUN([GD_PERL],
 [
 first_perl=5.8.0
-perl_prog_list="perl perl5 \
-perl5.14 perl5.12 perl5.10 perl5.8 \
-perl5.14.0 \
-perl5.12.3 perl5.12.2 perl5.12.1 perl5.12.0 \
-perl5.10.1 perl5.10.0 \
-perl5.8.9 perl5.8.8 perl5.8.7 perl5.8.6 perl5.8.5 perl5.8.4 perl5.8.3 \
-perl5.8.2 perl5.8.1 perl5.8.0"
+perl_prog_list="perl perl5"
 
 dnl --without-perl basically does the same as --disable-perl
 AC_ARG_WITH([perl], AS_HELP_STRING([--with-perl=PATH],
@@ -166,22 +161,35 @@ if test "x${have_perl}" != "xno"; then
   dnl calculate the extension module directory
   AC_MSG_CHECKING([Perl module directory])
   if test $perl_inst_type = "vendor"; then
-    GD_PERL_CONFIG([perldir], [vendorarchexp])
-    GD_PERL_CONFIG([perlmandir], [vendorman3direxp])
+    GD_PERL_CONFIG([perlprefix], [vendorprefix])
+    GD_PERL_CONFIG([prefixed_perldir], [vendorarchexp])
+    GD_PERL_CONFIG([prefixed_perlmandir], [vendorman3direxp])
     if test perldir = "UNKNOWN"; then
       perl_inst_type = "site";
     fi
   fi
 
   if test $perl_inst_type = "site"; then
-    GD_PERL_CONFIG([perldir], [sitearchexp])
-    GD_PERL_CONFIG([perlmandir], [siteman3direxp])
-  elif test $perl_inst_type != "vendor"; then
+    GD_PERL_CONFIG([perlprefix], [siteprefix])
+    GD_PERL_CONFIG([prefixed_perldir], [sitearchexp])
+    GD_PERL_CONFIG([prefixed_perlmandir], [siteman3direxp])
+  fi
+
+  if test $perl_inst_type = "local"; then
     perldir="${local_perl_path}"
     perlmandir="UNKNOWN"
+  elif test "x$SED" != "x"; then
+    esc_perlprefix=$(echo ${perlprefix} | ${SED} -e 's/\//\\\//g')
+    perldir=$(echo ${prefixed_perldir} | \
+        ${SED} -e "s/^${esc_perlprefix}/\${exec_prefix}/")
+    perlmandir=$(echo ${prefixed_perlmandir} | \
+        ${SED} -e "s/^${esc_perlprefix}/\${prefix}/")
+  else
+    perldir=${prefixed_perldir}
+    perlmandir=${prefixed_perlmandir}
   fi
 
-  if test $perlmandir = "UNKNOWN"; then
+  if test "x$perlmandir" = "xUNKNOWN"; then
     perlmandir="${mandir}/man3"
   fi
 
diff --git a/m4/php.m4 b/m4/php.m4
index a831adf..3024a19 100644
--- a/m4/php.m4
+++ b/m4/php.m4
@@ -64,6 +64,13 @@ if test "x${have_php}" != "xno"; then
   AC_SUBST([PHP_CONFIG])
 fi
 
+dnl php CLI
+if test "x${have_php}" != "xno"; then
+  AC_MSG_CHECKING([PHP interpreter path])
+  GD_PHP_CONFIG([PHP], [php-binary], [UNKNOWN])
+  AC_MSG_RESULT([$PHP])
+fi
+
 dnl extension dir
 AC_ARG_WITH([php-dir], AS_HELP_STRING([--with-php-dir=DIR],
       [install the GetData PHP extension into DIR [default: autodetect]]),
@@ -75,23 +82,21 @@ AC_ARG_WITH([php-dir], AS_HELP_STRING([--with-php-dir=DIR],
       fi
       ], [phpdir=UNKNOWN])
 
-dnl php CLI
-if test "x${have_php}" != "xno"; then
-  AC_MSG_CHECKING([PHP interpreter path])
-  GD_PHP_CONFIG([PHP], [php-binary], [UNKNOWN])
-  AC_MSG_RESULT([$PHP])
-fi
-
 if test "x${have_php}" != "xno"; then
   AC_SUBST([PHP])
   AC_MSG_CHECKING([the PHP extension directory])
   if test "x${phpdir}" = "xUNKNOWN"; then
-    GD_PHP_CONFIG([phpdir], [extension-dir], [UNKNOWN])
+    GD_PHP_CONFIG([phpprefix], [prefix], [UNKNOWN])
+    GD_PHP_CONFIG([prefixed_phpdir], [extension-dir], [UNKNOWN])
+    if test "x${prefixed_phpdir}" = "xUNKNOWN"; then
+      phpdir=${libdir}/php/extensions
+    elif test "x${SED}" != "x"; then
+      esc_phpprefix=$(echo ${phpprefix} | ${SED} -e 's/\//\\\//g')
+      phpdir=$(echo ${prefixed_phpdir} | \
+          ${SED} -e "s/^${esc_phpprefix}/\${exec_prefix}/")
+    fi
   fi
   AC_MSG_RESULT([$phpdir])
-  if test "x${phpdir}" = "xUNKNOWN"; then
-    have_php=no
-  fi
   AC_SUBST([phpdir])
 
   AC_MSG_CHECKING([PHP CPPFLAGS])
diff --git a/m4/python.m4 b/m4/python.m4
index 6146269..92127fd 100644
--- a/m4/python.m4
+++ b/m4/python.m4
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2009, 2011, 2013 D. V. Wiebe
+dnl Copyright (C) 2009, 2011, 2013, 2016 D. V. Wiebe
 dnl
 dnl llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
 dnl
@@ -18,24 +18,83 @@ dnl You should have received a copy of the GNU Lesser General Public License
 dnl along with GetData; if not, write to the Free Software Foundation, Inc.,
 dnl 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
+dnl GD_LOG_SHELL(STUFF)
+dnl ---------------------------------------------------------------
+dnl Run STUFF as a shell command and log it
+AC_DEFUN([AM_LOG_SHELL],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ac_status=$?
+echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+(exit $ac_status); }])
+
+dnl GD_PYTHON_CONFIGVAR(VAR, KEY)
+dnl ---------------------------------------------------------------
+dnl Store the value of config_var KEY in VAR
+AC_DEFUN([GD_PYTHON_CONFIGVAR],
+[
+  $1=$(${PYTHON} - <<EOF 2>/dev/null
+try:
+  import sysconfig
+except ImportError:
+  from distutils import sysconfig
+
+print (sysconfig.get_config_var("$2"))
+EOF
+)
+
+  if test "x${$1}" = "x"; then $1=None; fi
+])
+
+dnl GD_PYTHON3(PROG)
+dnl ---------------------------------------------------------------
+dnl If PROG is a Python3 interpreter, set have_python3 to "yes"
+dnl otherwise set it to "no"
+AC_DEFUN([GD_PYTHON3],
+[
+AS_IF(AM_LOG_SHELL(
+    [$1 -c 'import sys; sys.exit(int(sys.version@<:@:1@:>@) - 3)']
+  ), [have_python3=yes],[have_python3=no])
+])
+
+dnl GD_PYTHON_MIN_VERSION(PROG,VERSION2,VERSION3,ACTION-IF-TRUE,ACTION-IF_FALSE)
+dnl ---------------------------------------------------------------
+dnl Make sure Python interpreter PROG is at least VERSION2 for Python2 or
+dnl VERSION3 for Python3.  If new enough, run ACTION-IF-TRUE, otherwise
+dnl run ACTION-IF-FALSE.
+AC_DEFUN([GD_PYTHON_MIN_VERSION],
+[
+GD_PYTHON3([$1])
+if test "$have_python3" = "no"; then
+  AM_PYTHON_CHECK_VERSION([$1],[$2],[$4],[$5])
+else
+  AM_PYTHON_CHECK_VERSION([$1],[$3],[$4],[$5])
+fi
+])
+
 dnl GD_PYTHON
 dnl ---------------------------------------------------------------
-dnl Look for python.  Then determine whether we can build extension modules.
+dnl Look for Python.  Then determine whether we can build extension modules.
 AC_DEFUN([GD_PYTHON],
 [
-last_python=2.7
-first_python=$1
+first_python2=$1
+last_python2=2.7
+
+first_python3=$2
+last_python3=3.9 dnl have to stop somewhere
 
 if test "x$SEQ" == "xnot found"; then
   if test "x$JOT" == "xnot found"; then
-    python_prog_list="python python2"
+    python_prog_list="python python3 python2"
   else
-    python_prog_list="python python2 dnl
-    `$JOT -w 'python%.1f' - $last_python $first_python -0.1`" #'
+    python_prog_list="python dnl
+    python3 `$JOT -w 'python%.1f' - $last_python3 $first_python3 -0.1` dnl
+    python2 `$JOT -w 'python%.1f' - $last_python2 $first_python2 -0.1`" #'
   fi
 else
-  python_prog_list="python python2 dnl
-  `$SEQ -f 'python%.1f' $last_python -0.1 $first_python`" #'
+  python_prog_list="python dnl
+  python3 `$SEQ -f 'python%.1f' $last_python3 -0.1 $first_python3` dnl
+  python2 `$SEQ -f 'python%.1f' $last_python2 -0.1 $first_python2`" #'
 fi
 
 dnl --without-python basically does the same as --disable-python
@@ -60,23 +119,24 @@ AC_ARG_WITH([python-module-dir], AS_HELP_STRING([--with-python-module-dir=PATH],
 
 if test "x${have_python}" != "xno"; then
 
-dnl try to find a sufficiently new python.
+dnl try to find a sufficiently new Python - it would be nice to use
+dnl AM_PATH_PYTHON, but it's buggy.
 if test "x$user_python" != "x"; then
-  AC_MSG_CHECKING([whether $user_python version >= $first_python])
-  AM_PYTHON_CHECK_VERSION([$user_python], [$first_python],
+  AC_MSG_CHECKING([whether $user_python is new enough])
+  GD_PYTHON_MIN_VERSION([$user_python], [$first_python2], [$first_python3],
   [AC_MSG_RESULT([yes])
   PYTHON=$user_python],
   [AC_MSG_RESULT([no])
   PYTHON="not found"])
 else
-  AC_MSG_CHECKING([for Python interpreter version >= $first_python])
+  AC_MSG_CHECKING([for Python interpreter version >= $first_python2])
   PYTHON="not found"
   for py in $python_prog_list; do
   _AS_PATH_WALK([$PATH],
   [for exec_ext in '' $ac_executable_extensions; do
     if AS_EXECUTABLE_P(["$as_dir/$py$exec_ext"]); then
-      AM_PYTHON_CHECK_VERSION( ["$as_dir/$py$exec_ext"],
-      [$first_python], [ PYTHON="$as_dir/$py$exec_ext"; break 3] )
+      GD_PYTHON_MIN_VERSION( ["$as_dir/$py$exec_ext"], [$first_python2],
+      [$first_python3], [ PYTHON="$as_dir/$py$exec_ext"; break 3] )
     fi
   done])
   done
@@ -92,43 +152,95 @@ AC_SUBST([PYTHON])
 fi
 
 if test "x${have_python}" != "xno"; then
-dnl python version
+
+dnl Python version
+AC_MSG_CHECKING([if we're using a Python3 interpreter])
+AC_MSG_RESULT([$have_python3])
+
 AC_MSG_CHECKING([$PYTHON version])
-PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[[:3]]"`
+PYTHON_VERSION=`$PYTHON -c "import sys; print (sys.version[[:3]])"`
 AC_MSG_RESULT([$PYTHON_VERSION])
 AC_SUBST([PYTHON_VERSION])
 
-dnl calculate python CPPFLAGS
-AC_MSG_CHECKING([Python includes])
-if test -x $PYTHON-config; then
-  PYTHON_CPPFLAGS=`$PYTHON-config --includes 2>/dev/null`
-else
-  python_prefix=`$PYTHON -c "import sys; print sys.prefix"`
-  python_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
-  PYTHON_CPPFLAGS="-I${python_prefix}/include/python${PYTHON_VERSION} -I${python_exec_prefix}/include/python${PYTHON_VERSION}"
+dnl Python ABI version (which can be different than VERISON in python3)
+AC_MSG_CHECKING([Python ABI version])
+GD_PYTHON_CONFIGVAR([PYTHON_LDVERSION], [LDVERSION])
+if test "${PYTHON_LDVERSION}" = "None"; then
+  PYTHON_LDVERSION=${PYTHON_VERSION}
+fi
+AC_MSG_RESULT([$PYTHON_LDVERSION])
+
+dnl calculate Python CPPFLAGS
+AC_MSG_CHECKING([Python CPPFLAGS])
+python_prefix=`$PYTHON -c "import sys; print (sys.prefix)"`
+python_exec_prefix=`$PYTHON -c "import sys; print (sys.exec_prefix)"`
+PYTHON_CPPFLAGS="-I${python_prefix}/include/python${PYTHON_LDVERSION}"
+if test "x${python_prefix}" != "x${python_exec_prefix}"; then
+  PYTHON_CPPFLAGS="${PYTHON_CPPFLAGS} -I${python_exec_prefix}/include/python${PYTHON_LDVERSION}"
 fi
 AC_MSG_RESULT([$PYTHON_CPPFLAGS])
 
+dnl calculate Python LDFLAGS -- only needed during configure
+AC_MSG_CHECKING([Python LDFLAGS])
+GD_PYTHON_CONFIGVAR([PYTHON_LIBDIR], [LIBDIR])
+PYTHON_LDFLAGS="-L${PYTHON_LIBDIR} -lpython${PYTHON_LDVERSION}"
+AC_MSG_RESULT([$PYTHON_LDFLAGS])
+
 dnl figure out the platform name
 AC_MSG_CHECKING([Python platform name])
-PYTHON_PLATFORM=`$PYTHON -c "from distutils import util; print util.get_platform()"`
+PYTHON_PLATFORM=`$PYTHON -c \
+  "from distutils import util; print (util.get_platform())"`
 AC_MSG_RESULT([$PYTHON_PLATFORM])
 AC_SUBST([PYTHON_PLATFORM])
 
-dnl calculate the exec prefix
-pyexec_prefix=$exec_prefix
-test "x$pyexec_prefix" = xNONE && pyexec_prefix=$prefix
-test "x$pyexec_prefix" = xNONE && pyexec_prefix=$ac_default_prefix
-
 dnl calculate the extension module directory
 AC_MSG_CHECKING([Python extension module directory])
 if test "x${local_python_modpath}" = "x"; then
-  pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='${pyexec_prefix}')" 2>/dev/null || echo "${pyexec_prefix}/lib/python${PYTHON_VERSION}/site-packages"`
+  pythondir=$(${PYTHON} - <<EOF 2>/dev/null
+import sys
+if sys.version[[:1]] == '3':
+  import sysconfig
+  print (sysconfig.get_path('platlib', vars={'platbase': '\${exec_prefix}'}))
+else:
+  from distutils import sysconfig
+  print (sysconfig.get_python_lib(1,0,prefix='\${exec_prefix}'))
+EOF
+)
+  if test "x${pythondir}" = "xNone" -o "x${pythondir}" = "x"; then
+    pythondir='\${exec_prefix}/lib/python${PYTHON_LDVERSION}/site-packages'
+  fi
 else
   pythondir=$local_python_modpath
 fi
-AC_SUBST([pythondir])
 AC_MSG_RESULT([$pythondir])
+AC_SUBST([pythondir])
+
+dnl figure out object suffix
+AC_MSG_CHECKING([Python object suffix])
+GD_PYTHON_CONFIGVAR([PYTHON_OBJECT_SUFFIX], [SO])
+if test "x${PYTHON_OBJECT_SUFFIX}" = "xNone"; then
+  GD_PYTHON_CONFIGVAR([PYTHON_OBJECT_SUFFIX], [EXT_SUFFIX])
+fi
+AC_MSG_RESULT([$PYTHON_OBJECT_SUFFIX])
+AC_SUBST([PYTHON_OBJECT_SUFFIX])
+
+if test "$have_python3" = "no"; then
+saved_CPPFLAGS=${CPPFLAGS}
+CPPFLAGS="${PYTHON_CPPFLAGS} ${CPPFLAGS}"
+AC_CHECK_DECLS([Py_USING_UNICODE],[have_pyunicode=yes],
+    [have_pyunicode="no (required)"], [
+#include <Python.h>
+    ])
+CPPFLAGS=${saved_CPPFLAGS}
+else
+have_pyunicode=yes
+fi
+
+AC_MSG_CHECKING([for Unicode support in Python])
+if test "${have_pyunicode}" != "yes"; then
+  have_python=no
+fi
+AC_MSG_RESULT([$have_pyunicode])
 
 fi
 ])
diff --git a/m4/version.m4 b/m4/version.m4
index ed46a49..c347ed6 100644
--- a/m4/version.m4
+++ b/m4/version.m4
@@ -20,9 +20,9 @@ dnl 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 m4_define(getdata_major,    0)
 m4_define(getdata_minor,    9)
-m4_define(getdata_revision, 2)
+m4_define(getdata_revision, 3)
 m4_define(getdata_extra,    [])
-m4_define(getdata_pkg_extra,[.1])
+m4_define(getdata_pkg_extra,[])
 m4_define(getdata_version,
           getdata_major.getdata_minor.getdata_revision[]getdata_extra)
 m4_define(getdata_pkg_version,
@@ -31,12 +31,12 @@ m4_define(getdata_pkg_version,
 dnl libgetdata current interface version
 m4_define(getdata_iface_version,    7)
 dnl libgetdata current interface implementation revision
-m4_define(getdata_impl_revision,    2)
+m4_define(getdata_impl_revision,    3)
 dnl libgetdata interface age (current interface - oldest supported interface)
 m4_define(getdata_iface_age,        0)
 
 dnl libgetdata++ interface version info
-m4_define(getdataxx_version, 6:0:0)
+m4_define(getdataxx_version, 6:1:0)
 
 dnl libfgetdata interface version info
 m4_define(fgetdata_version, 5:0:0)
diff --git a/m4/win32.m4 b/m4/win32.m4
index c8e4b22..17f1f29 100644
--- a/m4/win32.m4
+++ b/m4/win32.m4
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2010, 2011 D. V. Wiebe
+dnl Copyright (C) 2010, 2011, 2016 D. V. Wiebe
 dnl
 dnl llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
 dnl
@@ -33,7 +33,7 @@ AC_MSG_RESULT([$this_is_msys])
 
 if test "$this_is_msys" = "yes"; then
 AC_MSG_CHECKING([for the Win32 MSYS shell])
-msys_root=`mount | ${GREP} 'on / ' | awk '{print [$]1}'`
+msys_root=`mount | ${AWK} '/on \/ / {print [$]1}'`
 msys_shell1="$msys_root`echo $SHELL | ${SED} -e 's/\//\\\\/g'`.exe"
 msys_shell=`echo "$msys_shell1" | ${SED} -e 's/\\\\/\\\\\\\\/g'`
 AC_MSG_RESULT([$msys_shell1])
diff --git a/man/Makefile.in b/man/Makefile.in
index 7b55cac..1e844ae 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -302,6 +302,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -351,6 +352,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
diff --git a/man/dirfile-format.5 b/man/dirfile-format.5
index 4fabc3e..131fdc1 100644
--- a/man/dirfile-format.5
+++ b/man/dirfile-format.5
@@ -1010,7 +1010,7 @@ Standards Version 9 deprecates these two aliases, but still allows them.
 
 All these type names (except those for complex data, which came later) were
 introduced in Standards Version 5.  Earlier Standards Versions specified data
-types with single character type aliases:
+types with single-character type aliases:
 
 .RS
 .TP
@@ -1040,8 +1040,8 @@ Types
 .IR INT8 ", " UINT64 ", " INT64 ", " COMPLEX64 ,
 and
 .I COMPLEX128
-are not supported before Standards Version 5, so no single character type
-aliases exist for these types.  These single character type aliases were
+are not supported before Standards Version 5, so no single-character type
+aliases exist for these types.  These single-character type aliases were
 deprecated in Standards Version 5 and removed in Standards Version 8.
 .RE
 .TP
@@ -1452,7 +1452,7 @@ Version 8 of the Standards (November 2010) added the
 and
 .B CARRAY
 field types, made the forward slash on reserved words mandatory, and prohibited
-using the single character data type aliases in the specification of
+using the single-character type aliases in the specification of
 .B RAW
 fields.  It also introduced the optional second
 .RI ( arm )
diff --git a/man/gd_carrays.3 b/man/gd_carrays.3
index f79e5ab..f6bb364 100644
--- a/man/gd_carrays.3
+++ b/man/gd_carrays.3
@@ -1,6 +1,6 @@
 .\" gd_carrays.3.  The gd_carrays man page.
 .\"
-.\" Copyright (C) 2010, 2011 D. V. Wiebe
+.\" Copyright (C) 2010, 2011, 2016 D. V. Wiebe
 .\"
 .\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .\"
@@ -13,7 +13,7 @@
 .\" Texts.  A copy of the license is included in the `COPYING.DOC' file
 .\" as part of this distribution.
 .\"
-.TH gd_carrays 3 "17 August 2011" "Version 0.8.0" "GETDATA"
+.TH gd_carrays 3 "19 April 2016" "Version 0.9.3" "GETDATA"
 .SH NAME
 gd_carrays \(em retrieve a list of CARRAY values from a dirfile
 .SH SYNOPSIS
@@ -97,7 +97,12 @@ specifies the length of the
 .B CARRAY
 data, and
 .I d
-is an array of the data values themselves.  The caller should cast the
+is an array of the data values themselves. If
+.I return_type
+was
+.BR GD_NULL ,
+.I d
+will be NULL.  Otherwise, the caller should cast the
 .B void
 pointer to a type appropriate for the
 .I return_type
diff --git a/man/gd_verbose_prefix.3 b/man/gd_verbose_prefix.3
index 017084b..00d3c36 100644
--- a/man/gd_verbose_prefix.3
+++ b/man/gd_verbose_prefix.3
@@ -1,6 +1,6 @@
 .\" gd_verbose_prefix.3.  The gd_verbose_prefix man page.
 .\"
-.\" Copyright (C) 2012 D. V. Wiebe
+.\" Copyright (C) 2012, 2016 D. V. Wiebe
 .\"
 .\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .\"
@@ -13,7 +13,7 @@
 .\" Texts.  A copy of the license is included in the `COPYING.DOC' file
 .\" as part of this distribution.
 .\"
-.TH gd_verbose_prefix 3 "1 April 2012" "Version 0.8.0" "GETDATA"
+.TH gd_verbose_prefix 3 "12 May 2016" "Version 0.9.3" "GETDATA"
 .SH NAME
 gd_verbose_prefix \(em set the prefix on error messages printed by GetData
 .SH SYNOPSIS
@@ -47,9 +47,8 @@ is set, when the library encounters an error, it prints the supplied prefix (if
 any), followed immediately by the error message (which is the message returned
 by
 .BR gd_error_string (3)),
-followed by a newline.  All output goes to the standard error I/O stream
-.RB ( stderr (3))
-of the caller.
+followed by a newline.  All output goes to the caller's standard error
+.RB ( stderr (3)).
 
 The 
 .I dirfile
@@ -59,14 +58,11 @@ argument must point to a valid DIRFILE object previously created by a call to
 .SH RETURN VALUE
 Upon successful completion,
 .BR gd_verbose_prefix ()
-returns the zero.  On error, it returns -1 and sets the dirfile error
+returns zero.  On error, it returns -1 and sets the dirfile error
 to a non-zero error value.  Possible error values are:
 .TP
 .B GD_E_ALLOC
 The library was unable to allocate memory.
-.TP
-.B GD_E_BAD_DIRFILE
-The supplied dirfile was invalid.
 .PP
 The dirfile error may be retrieved by calling
 .BR gd_error (3).
diff --git a/src/Makefile.am b/src/Makefile.am
index 2fc8b92..43b96ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2013, 2015 D. V. Wiebe
+# Copyright (C) 2008-2013, 2015, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -134,7 +134,7 @@ libgetdata_la_SOURCES = add.c ascii.c ${BZIP2_C} close.c common.c compat.c \
 												mod.c move.c name.c native.c nfields.c nframes.c \
 												open.c parse.c protect.c putdata.c raw.c sie.c \
 												${SLIM_C} spf.c string.c types.c ${ZZIP_C} ${ZZSLIM_C} \
-												${GETDATA_LEGACY_H} internal.h
+												${GETDATA_LEGACY_H} gd_extra_config.h internal.h
 libgetdata_la_LDFLAGS = $(EXPORT_DYNAMIC) -export-symbols-regex '^[^_]' \
 												-version-info \
 												${GETDATA_IFACE_VERSION}:${GETDATA_IMPL_REVISION}:${GETDATA_IFACE_AGE} \
diff --git a/src/Makefile.in b/src/Makefile.in
index ba63714..337022f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -153,7 +153,8 @@ am__libgetdata_la_SOURCES_DIST = add.c ascii.c bzip.c close.c common.c \
 	getdata.c globals.c gzip.c index.c include.c iopos.c legacy.c \
 	lzma.c mod.c move.c name.c native.c nfields.c nframes.c open.c \
 	parse.c protect.c putdata.c raw.c sie.c slim.c spf.c string.c \
-	types.c zzip.c zzslim.c getdata_legacy.h internal.h
+	types.c zzip.c zzslim.c getdata_legacy.h gd_extra_config.h \
+	internal.h
 @USE_BZIP2_TRUE@@USE_MODULES_FALSE at am__objects_1 = bzip.lo
 @GETDATA_DEBUG_TRUE at am__objects_2 = debug.lo
 @USE_FLAC_TRUE@@USE_MODULES_FALSE at am__objects_3 = flac.lo
@@ -455,6 +456,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -504,6 +506,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -545,7 +548,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2008-2013, 2015 D. V. Wiebe
+# Copyright (C) 2008-2013, 2015, 2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -622,7 +625,7 @@ libgetdata_la_SOURCES = add.c ascii.c ${BZIP2_C} close.c common.c compat.c \
 												mod.c move.c name.c native.c nfields.c nframes.c \
 												open.c parse.c protect.c putdata.c raw.c sie.c \
 												${SLIM_C} spf.c string.c types.c ${ZZIP_C} ${ZZSLIM_C} \
-												${GETDATA_LEGACY_H} internal.h
+												${GETDATA_LEGACY_H} gd_extra_config.h internal.h
 
 libgetdata_la_LDFLAGS = $(EXPORT_DYNAMIC) -export-symbols-regex '^[^_]' \
 												-version-info \
diff --git a/src/common.c b/src/common.c
index ef3ff11..efbe58f 100644
--- a/src/common.c
+++ b/src/common.c
@@ -46,7 +46,7 @@ char *_GD_GetLine(FILE *restrict fp, size_t *restrict n, int *restrict linenum)
 
   char *line = NULL;
 
-  dtrace("%p, %p, %p", fp, n, linenum);
+  dtrace("%p, %p, %p(%i)", fp, n, linenum, *linenum);
 
   do {
     errno = 0;
@@ -59,12 +59,12 @@ char *_GD_GetLine(FILE *restrict fp, size_t *restrict n, int *restrict linenum)
 
 
   if (len != -1) {
-    dreturn("\"%s\" (%" PRIuSIZE ")", line, *n);
+    dreturn("%i: \"%s\" (%" PRIuSIZE ")", *linenum, line, *n);
     return line; /* a line was read */
   }
 
   free(line);
-  dreturn("%p", NULL);
+  dreturn("%i: %p", *linenum, NULL);
   return NULL;  /* there were no valid lines */
 }
 
@@ -219,6 +219,12 @@ int _GD_SetTablePath(DIRFILE *restrict D, const gd_entry_t *restrict E,
 
   e->u.linterp.table_dirfd = _GD_GrabDir(D,
       D->fragment[E->fragment_index].dirfd, E->EN(linterp,table), 0);
+  if (e->u.linterp.table_dirfd < 0 && D->error == GD_E_OK)
+    _GD_SetError(D, GD_E_IO, GD_E_IO_OPEN, E->EN(linterp,table), 0, NULL);
+  if (D->error) {
+    dreturn("%i", 1);
+    return 1;
+  }
 
   temp_buffer = _GD_Strdup(D, E->EN(linterp,table));
   if (temp_buffer == NULL) {
diff --git a/src/gd_config.h.in b/src/gd_config.h.in
index 33a5aad..76479b4 100644
--- a/src/gd_config.h.in
+++ b/src/gd_config.h.in
@@ -118,6 +118,10 @@
    don't. */
 #undef HAVE_DECL_PUT_UNALIGNED
 
+/* Define to 1 if you have the declaration of `Py_USING_UNICODE', and to 0 if
+   you don't. */
+#undef HAVE_DECL_PY_USING_UNICODE
+
 /* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
    don't. */
 #undef HAVE_DECL_STRERROR_R
@@ -290,6 +294,12 @@
 /* Define to 1 if you have the <pthread.h> header file. */
 #undef HAVE_PTHREAD_H
 
+/* Define to 1 if you have the `PyCapsule_New' function. */
+#undef HAVE_PYCAPSULE_NEW
+
+/* Define to 1 if you have the `PyErr_NewExceptionWithDoc' function. */
+#undef HAVE_PYERR_NEWEXCEPTIONWITHDOC
+
 /* Define to 1 if you have the `readdir_r' function. */
 #undef HAVE_READDIR_R
 
@@ -763,3 +773,5 @@
 
 /* Define as `fork' if `vfork' does not work. */
 #undef vfork
+
+#include "gd_extra_config.h"
diff --git a/test/del_bad_code.c b/src/gd_extra_config.h
similarity index 66%
copy from test/del_bad_code.c
copy to src/gd_extra_config.h
index 1595d4e..a0d6d6f 100644
--- a/test/del_bad_code.c
+++ b/src/gd_extra_config.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 D. V. Wiebe
+/* Copyright (C) 2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -18,27 +18,25 @@
  * along with GetData; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include "test.h"
+#ifndef GETDATA_EXTRA_CONFIG_H
+#define GETDATA_EXTRA_CONFIG_H
 
-int main(void)
-{
-  const char *filedir = "dirfile";
-  const char *format = "dirfile/format";
-  int fd, h1, e1, r = 0;
-  DIRFILE *D;
+/* Deal with Apple Universal builds */
+#ifdef __APPLE__
 
-  rmdirfile();
+# undef SIZEOF_LONG
+# undef SIZEOF_SIZE_T
+# undef SIZEOF_VOID_P
 
-  D = gd_open(filedir, GD_RDWR | GD_CREAT | GD_EXCL);
-  h1 = gd_delete(D, "something", 0);
-  e1 = gd_error(D);
+# ifdef __LP64__
+#   define SIZEOF_LONG   8
+#   define SIZEOF_SIZE_T 8
+#   define SIZEOF_VOID_P 8
+# else
+#   define SIZEOF_LONG   4
+#   define SIZEOF_SIZE_T 4
+#   define SIZEOF_VOID_P 4
+# endif
+#endif
 
-  CHECKI(e1, GD_E_BAD_CODE);
-  CHECKI(h1, -1);
-
-  gd_discard(D);
-  unlink(format);
-  rmdir(filedir);
-
-  return r;
-}
+#endif
diff --git a/src/getdata.h.in b/src/getdata.h.in
index ec99e7f..6276e79 100644
--- a/src/getdata.h.in
+++ b/src/getdata.h.in
@@ -169,7 +169,7 @@ extern "C" {
 /* the maximum number of input vectors in a LINCOM */
 #define GD_MAX_LINCOM 3
 
-/* the following MUST be at least one less than twice GD_MAX_LINCOM */
+/* the following MUST be at most one less than twice GD_MAX_LINCOM */
 #define GD_MAX_POLYORD (GD_MAX_LINCOM * 2 - 1)
 
 /* syntax suberrors */
diff --git a/src/globals.c b/src/globals.c
index d65739b..ff00378 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -138,12 +138,6 @@ int gd_verbose_prefix(DIRFILE *D, const char *prefix) gd_nothrow
   char *ptr = NULL;
   dtrace("%p, \"%s\"", D, prefix);
 
-  if (D->flags & GD_INVALID) {
-    _GD_SetError(D, GD_E_BAD_DIRFILE, 0, NULL, 0, NULL);
-    dreturn("%i", -1);
-    return -1;
-  }
-
   _GD_ClearError(D);
 
   if (prefix) {
diff --git a/src/include.c b/src/include.c
index aaee504..ec3c763 100644
--- a/src/include.c
+++ b/src/include.c
@@ -295,6 +295,10 @@ int _GD_Include(DIRFILE *D, struct parser_state *p, const char *ename,
     if (!oldp.pedantic)
       p->pedantic = 0;
   }
+  
+  /* pop file location */
+  p->line = oldp.line;
+  p->file = oldp.file;
 
   /* pop namespace, if necessary */
   if (pop_ns) {
diff --git a/src/internal.h b/src/internal.h
index 40c4f43..1754eb2 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -111,7 +111,7 @@
 #define SIZEOF_SIZE_T (sizeof size_t)
 #endif
 
-/* MSCVRT defines ssize_t but not ssize_t */
+/* MSCVRT defines size_t but not ssize_t */
 #ifdef __MSVCRT__
 #if SIZEOF_SIZE_T == 8
 typedef __int64 ssize_t;
diff --git a/src/name.c b/src/name.c
index 2af95e3..e6dc4c5 100644
--- a/src/name.c
+++ b/src/name.c
@@ -262,14 +262,20 @@ int _GD_ValidateField(const char* field_code, int standards, int strict,
   if ((type == GD_VF_NAME) && (field_code[0] == '\0' || (strict &&
           ((len > 50 && standards < 5) || (len > 16 && standards < 3)))))
   {
-    dreturn("%i", 1);
+    dreturn("%i [a]", 1);
     return 1;
   }
 
   for (i = 0; i < len; ++i)
-    if (field_code[i] == '/' || field_code[i] < 0x20) {
+    if (field_code[i] == '/' || (
+          field_code[i] < 0x20
+#if CHAR_MIN != 0
+        && field_code[i] >= 0x00
+#endif
+        ))
+    {
       /* these characters are always forbidden */
-      dreturn("%i", 1);
+      dreturn("%i [b]", 1);
       return 1;
     } else if (strict && ((standards >= 5 && (field_code[i] == '<' ||
               field_code[i] == '>' || field_code[i] == ';' ||
@@ -277,21 +283,21 @@ int _GD_ValidateField(const char* field_code, int standards, int strict,
           (standards == 5 && (field_code[i] == '\\' || field_code[i] == '#'))))
     {
       /* these characters are sometimes forbidden */
-      dreturn("%i", 1);
+      dreturn("%i [c]", 1);
       return 1;
     } else if (field_code[i] == '.') {
       if (type == GD_VF_NS ||
           (type == GD_VF_CODE && (!strict || standards >= 10)))
       {
         if (last_dot) { /* multiple consecutive dots are forbidden */
-          dreturn("%i", 1);
+          dreturn("%i [d]", 1);
           return 1;
         }
         last_dot = 1;
       } else if (type == GD_VF_AFFIX || is_dot == NULL ||
           (standards >= 6 && strict))
       {
-        dreturn("%i", 1);
+        dreturn("%i [e]", 1);
         return 1;
       } else
         local_dot = 1;
@@ -300,7 +306,7 @@ int _GD_ValidateField(const char* field_code, int standards, int strict,
 
   /* Field codes may not end in a dot */
   if (type == GD_VF_CODE && last_dot) {
-    dreturn("%i", 1);
+    dreturn("%i [f]", 1);
     return 1;
   }
 
@@ -316,7 +322,7 @@ int _GD_ValidateField(const char* field_code, int standards, int strict,
           || (strcmp("PROTECT", field_code) == 0 && standards >= 6)
           || (strcmp("REFERENCE", field_code) == 0 && standards >= 6))
       {
-        dreturn("%i", 1);
+        dreturn("%i [g]", 1);
         return 1;
       }
   }
diff --git a/src/parse.c b/src/parse.c
index e0ccaee..4de580e 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -363,7 +363,7 @@ static int _GD_SetField(DIRFILE *restrict D,
   int offset;
   int is_dot = 0;
 
-  dtrace("%p, %p, %p, %p, %i, \"%s\", %i", D, p, E, P, me, name, no_dot);
+  dtrace("%p, %p{%s,%i}, %p, %p, %i, \"%s\", %i", D, p, p->file, p->line, E, P, me, name, no_dot);
 
   E->field = _GD_CodeFromFrag(D, p, P, me, name, NULL, &offset);
   if (E->field && _GD_ValidateField(E->field + offset, p->standards,
@@ -2411,7 +2411,6 @@ char *_GD_ParseFragment(FILE *restrict fp, DIRFILE *D, struct parser_state *p,
   char *outstring = NULL;
   const char *tok_pos = NULL;
   char *in_cols[MAX_IN_COLS];
-  int linenum = 0;
   char* ref_name = NULL;
   int n_cols;
   size_t n;
@@ -2420,7 +2419,6 @@ char *_GD_ParseFragment(FILE *restrict fp, DIRFILE *D, struct parser_state *p,
   int se_action = GD_SYNTAX_ABORT;
   gd_entry_t* first_raw = NULL;
   gd_parser_data_t pdata;
-
   int saved_error = 0;
   int saved_suberror = 0;
   int saved_line = 0;
@@ -2433,7 +2431,7 @@ char *_GD_ParseFragment(FILE *restrict fp, DIRFILE *D, struct parser_state *p,
   p->file = D->fragment[me].cname;
 
   /* start parsing */
-  while (rescan || (instring = _GD_GetLine(fp, &n, &linenum))) {
+  while (rescan || (instring = _GD_GetLine(fp, &n, &p->line))) {
     rescan = 0;
     n_cols = _GD_Tokenise(D, p, instring, &outstring, &tok_pos, MAX_IN_COLS,
         in_cols);
@@ -2465,7 +2463,7 @@ char *_GD_ParseFragment(FILE *restrict fp, DIRFILE *D, struct parser_state *p,
         }
         pdata.dirfile = D;
         pdata.suberror = D->suberror;
-        pdata.linenum = linenum;
+        pdata.linenum = p->line;
         pdata.filename = D->fragment[me].cname;
         pdata.line = instring;
         pdata.buflen = n;
diff --git a/src/sie.c b/src/sie.c
index ed4d405..a21b22a 100644
--- a/src/sie.c
+++ b/src/sie.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2015 D. V. Wiebe
+/* Copyright (C) 2011-2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -23,13 +23,23 @@
 /* define to debug this unit */
 #undef DEBUG_SIE
 
+/* Note: when using STDIO, glibc reads files in 4kiB chunks, so for small SIE
+ * files (4kiB = 170-455 records, depending on data size), all the I/O in this
+ * file happens in RAM, which probably means it's not terribly much slower than
+ * an in-RAM implementation like daisie, with the added benefit of not having
+ * to contort ourselves to play nice with the bookkeeping layer.
+ *
+ * On the other hand, this means we're basically unable to read SIE files
+ * concurrently (which we really shouldn't have expected to work anyways).
+ */
+
 #ifdef DEBUG_SIE
 #define dprintf_sie dprintf
 #else
 #define dprintf_sie(...)
 #endif
 
-#define DPRINTF dprintf_sie("F  r:%zi p:0x%" PRIX64 " s:%i,0x%" PRIX64 " " \
+#define DPRINTF dprintf_sie("F  r:%" PRIdSIZE " p:0x%" PRIX64 " s:%i,0x%" PRIX64 " " \
     "d:0x%" PRIX64 ",0x%" PRIX64 " l:%i/0x%" PRIX64 ",0x%" PRIX64 " @%li", \
     f->r, f->p, f->bof, f->s, f->d[0], f->d[1], f->have_l, f->l[0], f->l[1], \
     ftell(f->fp));
@@ -47,11 +57,60 @@ struct gd_siedata {
   int64_t l[3]; /* the previous record */
   int have_l; /* a flag to indicate that l is initialised */
   int bof;    /* this is the first record */
+  int header; /* non-zero if we have a header */
 };
 
+/* Header size in bytes */
+#define HEADSIZE 9
+
 /* correct for byte sex */
 #define FIXSEX(swap,v) ((swap) ? (int64_t)gd_swap64(v) : (v))
 
+static int _GD_SampIndDiscardHeader(FILE *stream)
+{
+  int have = 0;
+  unsigned char header[HEADSIZE];
+  static const unsigned char header_magic[8] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff };
+
+  dtrace("%p", stream);
+
+  if (fread(header, HEADSIZE, 1, stream) < 1) {
+    dreturn("%i", -1);
+    return -1;
+  }
+
+  /* Check for magic */
+#ifdef DEBUG_SIE
+  dprintf("header: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X "
+      "0x%02X", header[0], header[1], header[2], header[3], header[4],
+      header[5], header[6], header[7], header[8]);
+#endif
+  if (memcmp(header, header_magic, 8) == 0) {
+    int c;
+    /* We have magic, check for trailing data, which indicates there's another
+     * record (so what we have is indeed a header) */
+    c = getc(stream);
+    if (c == EOF) {
+      if (ferror(stream)) {
+        dreturn("%i", -1);
+        return -1;
+      } /* not a header; rewind so we can read it again */
+      rewind(stream);
+    } else { /* trailing data, unget it so it's available for the first read */
+      if (ungetc(c, stream) == EOF) {
+        dreturn("%i", -1);
+        return -1;
+      }
+      have = 1;
+    }
+  } else /* Bad header magic = no header: rewind */
+    rewind(stream);
+
+  dreturn("%i", have);
+  return have;
+}
+
 static int _GD_SampIndDoOpen(int fdin, struct gd_raw_file_ *file,
     struct gd_siedata *f, int swap, unsigned int mode)
 {
@@ -79,10 +138,21 @@ static int _GD_SampIndDoOpen(int fdin, struct gd_raw_file_ *file,
     return -1;
   }
 
+  if (!(mode & GD_FILE_WRITE)) {
+    f->header = _GD_SampIndDiscardHeader(stream);
+    if (f->header < 0) {
+      fclose(stream);
+      dreturn("%i", -1);
+      return -1;
+    }
+  } else
+    f->header = 0;
+
   memset(f, 0, sizeof(struct gd_siedata));
   f->r = f->s = f->p = f->d[0] = -1;
   f->fp = stream;
   f->swap = swap;
+
   dreturn("%i", fd);
   return fd;
 }
@@ -185,6 +255,16 @@ off64_t _GD_SampIndSeek(struct gd_raw_file_ *file, off64_t sample,
     /* seek backwards -- reading a file backwards doesn't necessarily work
      * that well.  So, let's just rewind to the beginning and try again. */
     rewind(f->fp);
+
+    /* Advance past header if necessary */
+    if (f->header) {
+      char header[HEADSIZE];
+      if (fread(header, HEADSIZE, 1, f->fp) < 1) {
+        dreturn("%i", -1);
+        return -1;
+      }
+    }
+
     file->idata = 0;
     f->r = f->s = f->p = f->d[0] = -1;
     f->bof = 1;
diff --git a/test/Makefile.am b/test/Makefile.am
index ea57288..6f82754 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 D. V. Wiebe
+# Copyright (C) 2008-2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -204,18 +204,19 @@ GET_TESTS=get64 get_affix get_bad_code get_bit get_carray get_carray_len \
 					get_lincom3 get_lincom3s get_lincom_mdt get_lincom_noin \
 					get_lincom_non get_lincom_null get_lincom_spf get_linterp \
 					get_linterp1 get_linterp_abs get_linterp_complex get_linterp_empty \
-					get_linterp_noin get_linterp_notab get_linterp_sort get_mplex \
-					get_mplex_bof get_mplex_complex get_mplex_lb get_mplex_lball \
-					get_mplex_nolb get_mplex_s get_mplex_saved get_multiply \
-					get_multiply_ccin get_multiply_crin get_multiply_crinr \
-					get_multiply_noin get_multiply_rcin get_multiply_s get_neg get_none \
-					get_nonexistent get_null get_off64 get_phase get_phase_affix \
-					get_polynom get_polynom_cmpin get_polynom_noin get_range get_recip \
-					get_recip_const get_recurse get_rofs get_sbit get_sf get_ss \
-					get_string get_type get_uint16 get_uint32 get_uint64 get_window \
-					get_window_clr get_window_complex get_window_ge get_window_gt \
-					get_window_le get_window_lt get_window_ne get_window_s \
-					get_window_set get_zero get_zero_complex get_zero_float
+					get_linterp_nodir get_linterp_noin get_linterp_notab \
+					get_linterp_sort get_mplex get_mplex_bof get_mplex_complex \
+					get_mplex_lb get_mplex_lball get_mplex_nolb get_mplex_s \
+					get_mplex_saved get_multiply get_multiply_ccin get_multiply_crin \
+					get_multiply_crinr get_multiply_noin get_multiply_rcin \
+					get_multiply_s get_neg get_none get_nonexistent get_null get_off64 \
+					get_phase get_phase_affix get_polynom get_polynom_cmpin \
+					get_polynom_noin get_range get_recip get_recip_const get_recurse \
+					get_rofs get_sbit get_sf get_ss get_string get_type get_uint16 \
+					get_uint32 get_uint64 get_window get_window_clr get_window_complex \
+					get_window_ge get_window_gt get_window_le get_window_lt \
+					get_window_ne get_window_s get_window_set get_zero get_zero_complex \
+					get_zero_float
 
 GLOBAL_TESTS=global_flags global_name global_ref global_ref_empty global_ref_set
 
@@ -373,11 +374,11 @@ SEEK_TESTS=seek64 seek_cur seek_end seek_far seek_foffs seek_foffs2 seek_index \
 					 seek_lincom seek_mult seek_neg seek_phase seek_range seek_range2 \
 					 seek_set seek_sub
 
-SIE_TESTS=sie_get_big sie_get_little sie_move_from sie_move_to sie_nframes_big \
-					sie_nframes_little sie_put_append sie_put_append2 sie_put_back \
-					sie_put_big sie_put_little sie_put_many sie_put_newo sie_put_newo0 \
-					sie_put_pad sie_put_pad0 sie_put_trunc sie_put_trunc2 \
-					sie_put_trunc_nf sie_seek sie_seek_far sie_sync
+SIE_TESTS=sie_get_big sie_get_header sie_get_little sie_move_from sie_move_to \
+					sie_nframes_big sie_nframes_little sie_put_append sie_put_append2 \
+					sie_put_back sie_put_big sie_put_header sie_put_little sie_put_many \
+					sie_put_newo sie_put_newo0 sie_put_pad sie_put_pad0 sie_put_trunc \
+					sie_put_trunc2 sie_put_trunc_nf sie_seek sie_seek_far sie_sync
 
 SLIM_TESTS=slim_get slim_nframes slim_seek slim_seek_far
 
diff --git a/test/Makefile.in b/test/Makefile.in
index 6a5e582..84bab74 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -410,21 +410,21 @@ am__EXEEXT_26 = get64$(EXEEXT) get_affix$(EXEEXT) \
 	get_lincom_null$(EXEEXT) get_lincom_spf$(EXEEXT) \
 	get_linterp$(EXEEXT) get_linterp1$(EXEEXT) \
 	get_linterp_abs$(EXEEXT) get_linterp_complex$(EXEEXT) \
-	get_linterp_empty$(EXEEXT) get_linterp_noin$(EXEEXT) \
-	get_linterp_notab$(EXEEXT) get_linterp_sort$(EXEEXT) \
-	get_mplex$(EXEEXT) get_mplex_bof$(EXEEXT) \
-	get_mplex_complex$(EXEEXT) get_mplex_lb$(EXEEXT) \
-	get_mplex_lball$(EXEEXT) get_mplex_nolb$(EXEEXT) \
-	get_mplex_s$(EXEEXT) get_mplex_saved$(EXEEXT) \
-	get_multiply$(EXEEXT) get_multiply_ccin$(EXEEXT) \
-	get_multiply_crin$(EXEEXT) get_multiply_crinr$(EXEEXT) \
-	get_multiply_noin$(EXEEXT) get_multiply_rcin$(EXEEXT) \
-	get_multiply_s$(EXEEXT) get_neg$(EXEEXT) get_none$(EXEEXT) \
-	get_nonexistent$(EXEEXT) get_null$(EXEEXT) get_off64$(EXEEXT) \
-	get_phase$(EXEEXT) get_phase_affix$(EXEEXT) \
-	get_polynom$(EXEEXT) get_polynom_cmpin$(EXEEXT) \
-	get_polynom_noin$(EXEEXT) get_range$(EXEEXT) \
-	get_recip$(EXEEXT) get_recip_const$(EXEEXT) \
+	get_linterp_empty$(EXEEXT) get_linterp_nodir$(EXEEXT) \
+	get_linterp_noin$(EXEEXT) get_linterp_notab$(EXEEXT) \
+	get_linterp_sort$(EXEEXT) get_mplex$(EXEEXT) \
+	get_mplex_bof$(EXEEXT) get_mplex_complex$(EXEEXT) \
+	get_mplex_lb$(EXEEXT) get_mplex_lball$(EXEEXT) \
+	get_mplex_nolb$(EXEEXT) get_mplex_s$(EXEEXT) \
+	get_mplex_saved$(EXEEXT) get_multiply$(EXEEXT) \
+	get_multiply_ccin$(EXEEXT) get_multiply_crin$(EXEEXT) \
+	get_multiply_crinr$(EXEEXT) get_multiply_noin$(EXEEXT) \
+	get_multiply_rcin$(EXEEXT) get_multiply_s$(EXEEXT) \
+	get_neg$(EXEEXT) get_none$(EXEEXT) get_nonexistent$(EXEEXT) \
+	get_null$(EXEEXT) get_off64$(EXEEXT) get_phase$(EXEEXT) \
+	get_phase_affix$(EXEEXT) get_polynom$(EXEEXT) \
+	get_polynom_cmpin$(EXEEXT) get_polynom_noin$(EXEEXT) \
+	get_range$(EXEEXT) get_recip$(EXEEXT) get_recip_const$(EXEEXT) \
 	get_recurse$(EXEEXT) get_rofs$(EXEEXT) get_sbit$(EXEEXT) \
 	get_sf$(EXEEXT) get_ss$(EXEEXT) get_string$(EXEEXT) \
 	get_type$(EXEEXT) get_uint16$(EXEEXT) get_uint32$(EXEEXT) \
@@ -679,11 +679,12 @@ am__EXEEXT_49 = seek64$(EXEEXT) seek_cur$(EXEEXT) seek_end$(EXEEXT) \
 	seek_index$(EXEEXT) seek_lincom$(EXEEXT) seek_mult$(EXEEXT) \
 	seek_neg$(EXEEXT) seek_phase$(EXEEXT) seek_range$(EXEEXT) \
 	seek_range2$(EXEEXT) seek_set$(EXEEXT) seek_sub$(EXEEXT)
-am__EXEEXT_50 = sie_get_big$(EXEEXT) sie_get_little$(EXEEXT) \
-	sie_move_from$(EXEEXT) sie_move_to$(EXEEXT) \
-	sie_nframes_big$(EXEEXT) sie_nframes_little$(EXEEXT) \
-	sie_put_append$(EXEEXT) sie_put_append2$(EXEEXT) \
-	sie_put_back$(EXEEXT) sie_put_big$(EXEEXT) \
+am__EXEEXT_50 = sie_get_big$(EXEEXT) sie_get_header$(EXEEXT) \
+	sie_get_little$(EXEEXT) sie_move_from$(EXEEXT) \
+	sie_move_to$(EXEEXT) sie_nframes_big$(EXEEXT) \
+	sie_nframes_little$(EXEEXT) sie_put_append$(EXEEXT) \
+	sie_put_append2$(EXEEXT) sie_put_back$(EXEEXT) \
+	sie_put_big$(EXEEXT) sie_put_header$(EXEEXT) \
 	sie_put_little$(EXEEXT) sie_put_many$(EXEEXT) \
 	sie_put_newo$(EXEEXT) sie_put_newo0$(EXEEXT) \
 	sie_put_pad$(EXEEXT) sie_put_pad0$(EXEEXT) \
@@ -2920,6 +2921,10 @@ get_linterp_empty_SOURCES = get_linterp_empty.c
 get_linterp_empty_OBJECTS = get_linterp_empty.$(OBJEXT)
 get_linterp_empty_LDADD = $(LDADD)
 get_linterp_empty_DEPENDENCIES = ../src/libgetdata.la
+get_linterp_nodir_SOURCES = get_linterp_nodir.c
+get_linterp_nodir_OBJECTS = get_linterp_nodir.$(OBJEXT)
+get_linterp_nodir_LDADD = $(LDADD)
+get_linterp_nodir_DEPENDENCIES = ../src/libgetdata.la
 get_linterp_noin_SOURCES = get_linterp_noin.c
 get_linterp_noin_OBJECTS = get_linterp_noin.$(OBJEXT)
 get_linterp_noin_LDADD = $(LDADD)
@@ -5124,6 +5129,10 @@ sie_get_big_SOURCES = sie_get_big.c
 sie_get_big_OBJECTS = sie_get_big.$(OBJEXT)
 sie_get_big_LDADD = $(LDADD)
 sie_get_big_DEPENDENCIES = ../src/libgetdata.la
+sie_get_header_SOURCES = sie_get_header.c
+sie_get_header_OBJECTS = sie_get_header.$(OBJEXT)
+sie_get_header_LDADD = $(LDADD)
+sie_get_header_DEPENDENCIES = ../src/libgetdata.la
 sie_get_little_SOURCES = sie_get_little.c
 sie_get_little_OBJECTS = sie_get_little.$(OBJEXT)
 sie_get_little_LDADD = $(LDADD)
@@ -5160,6 +5169,10 @@ sie_put_big_SOURCES = sie_put_big.c
 sie_put_big_OBJECTS = sie_put_big.$(OBJEXT)
 sie_put_big_LDADD = $(LDADD)
 sie_put_big_DEPENDENCIES = ../src/libgetdata.la
+sie_put_header_SOURCES = sie_put_header.c
+sie_put_header_OBJECTS = sie_put_header.$(OBJEXT)
+sie_put_header_LDADD = $(LDADD)
+sie_put_header_DEPENDENCIES = ../src/libgetdata.la
 sie_put_little_SOURCES = sie_put_little.c
 sie_put_little_OBJECTS = sie_put_little.$(OBJEXT)
 sie_put_little_LDADD = $(LDADD)
@@ -5761,80 +5774,80 @@ SOURCES = add_add.c add_affix.c add_alias.c add_alias_affix.c \
 	get_lincom_mdt.c get_lincom_noin.c get_lincom_non.c \
 	get_lincom_null.c get_lincom_spf.c get_linterp.c \
 	get_linterp1.c get_linterp_abs.c get_linterp_complex.c \
-	get_linterp_empty.c get_linterp_noin.c get_linterp_notab.c \
-	get_linterp_sort.c get_mplex.c get_mplex_bof.c \
-	get_mplex_complex.c get_mplex_lb.c get_mplex_lball.c \
-	get_mplex_nolb.c get_mplex_s.c get_mplex_saved.c \
-	get_multiply.c get_multiply_ccin.c get_multiply_crin.c \
-	get_multiply_crinr.c get_multiply_noin.c get_multiply_rcin.c \
-	get_multiply_s.c get_neg.c get_none.c get_nonexistent.c \
-	get_null.c get_off64.c get_phase.c get_phase_affix.c \
-	get_polynom.c get_polynom_cmpin.c get_polynom_noin.c \
-	get_range.c get_recip.c get_recip_const.c get_recurse.c \
-	get_rofs.c get_sbit.c get_sf.c get_ss.c get_string.c \
-	get_type.c get_uint16.c get_uint32.c get_uint64.c get_window.c \
-	get_window_clr.c get_window_complex.c get_window_ge.c \
-	get_window_gt.c get_window_le.c get_window_lt.c \
-	get_window_ne.c get_window_s.c get_window_set.c get_zero.c \
-	get_zero_complex.c get_zero_float.c global_flags.c \
-	global_name.c global_ref.c global_ref_empty.c global_ref_set.c \
-	gzip_add.c gzip_del.c gzip_get.c gzip_get_far.c gzip_get_get.c \
-	gzip_get_get2.c gzip_get_put.c gzip_move_from.c gzip_move_to.c \
-	gzip_nframes.c gzip_put.c gzip_put_back.c gzip_put_endian.c \
-	gzip_put_get.c gzip_put_nframes.c gzip_put_off.c \
-	gzip_put_pad.c gzip_put_sub.c gzip_seek.c gzip_seek_far.c \
-	gzip_seek_put.c gzip_sync.c header_complex.c header_off64t.c \
-	hide.c hide_bad.c hide_hidden.c hide_hidden_bad.c \
-	hide_unhide.c hide_unhide_bad.c include_accmode.c \
-	include_affix.c include_auto.c include_cb.c include_creat.c \
-	include_ignore.c include_include.c include_index.c \
-	include_invalid.c include_nonexistent.c include_pc.c \
-	include_ref.c include_sub.c include_syntax.c index_domain.c \
-	index_index.c index_range.c index_s.c index_subset.c \
-	legacy_error.c legacy_estring.c legacy_format.c legacy_get.c \
-	legacy_get_put.c legacy_get_rofs.c legacy_nframes.c \
-	legacy_nonexistent.c legacy_put.c legacy_spf.c lzma_get.c \
-	lzma_nframes.c lzma_put.c lzma_xz_add.c lzma_xz_get.c \
-	lzma_xz_get_far.c lzma_xz_get_get.c lzma_xz_get_get2.c \
-	lzma_xz_get_put.c lzma_xz_move_to.c lzma_xz_nframes.c \
-	lzma_xz_put.c lzma_xz_put_back.c lzma_xz_put_endian.c \
-	lzma_xz_put_get.c lzma_xz_put_pad.c lzma_xz_seek.c \
-	lzma_xz_seek_far.c lzma_xz_sync.c madd.c madd_affix.c \
-	madd_alias.c madd_alias_affix.c madd_bit.c madd_bit_invalid.c \
-	madd_carray.c madd_clincom.c madd_const.c madd_cpolynom.c \
-	madd_crecip.c madd_crecip89.c madd_divide.c madd_index.c \
-	madd_lincom.c madd_lincom_invalid.c madd_linterp.c \
-	madd_linterp_invalid.c madd_mplex.c madd_multiply.c \
-	madd_multiply_invalid.c madd_phase.c madd_phase_invalid.c \
-	madd_polynom.c madd_recip.c madd_sbit.c madd_spec.c \
-	madd_spec_directive.c madd_spec_invalid.c madd_spec_resolv.c \
-	madd_string.c madd_window.c move_affix.c move_affix_dup.c \
-	move_affix_meta.c move_affix_updb.c move_alias.c \
-	move_data_enc_ar.c move_data_enc_ra.c move_data_endian.c \
-	move_data_foffs.c move_data_foffs_neg.c move_data_nop.c \
-	move_index.c move_meta.c move_move.c move_protect.c \
-	move_subdir.c name_affix.c name_affix_bad.c name_alias.c \
-	name_dangle.c name_dot5.c name_dot5r.c name_dot9.c name_dup.c \
-	name_meta.c name_move.c name_move_alias.c name_name.c \
-	name_updb.c name_updb_affix.c name_updb_alias.c \
-	name_updb_carray.c name_updb_const.c name_updb_const_alias.c \
-	native_bit.c native_const.c native_index.c native_lincom.c \
-	native_lincom_cmpin.c native_lincom_cmpscal.c native_linterp.c \
-	native_linterp_cmp.c native_mult.c native_mult1.c \
-	native_mult2.c native_phase.c native_polynom.c \
-	native_polynom_cmpin.c native_polynom_cmpscal.c native_raw.c \
-	native_recip.c native_recip_cmpin.c native_recip_cmpscal.c \
-	native_sbit.c native_string.c nentries_alias.c \
-	nentries_hidden.c nentries_noalias.c nentries_scalar.c \
-	nfields_hidden.c nfields_invalid.c nfields_nfields.c \
-	nfields_type.c nfields_type_hidden.c nfields_type_invalid.c \
-	nfields_vector.c nfields_vector_hidden.c \
-	nfields_vector_invalid.c nframes64.c nframes_empty.c \
-	nframes_invalid.c nframes_nframes.c nframes_off64.c \
-	nframes_spf.c nmeta.c nmeta_hidden.c nmeta_invalid.c \
-	nmeta_parent.c nmeta_type.c nmeta_type_hidden.c \
-	nmeta_type_invalid.c nmeta_type_parent.c nmeta_vectors.c \
-	nmeta_vectors_del.c nmeta_vectors_hidden.c \
+	get_linterp_empty.c get_linterp_nodir.c get_linterp_noin.c \
+	get_linterp_notab.c get_linterp_sort.c get_mplex.c \
+	get_mplex_bof.c get_mplex_complex.c get_mplex_lb.c \
+	get_mplex_lball.c get_mplex_nolb.c get_mplex_s.c \
+	get_mplex_saved.c get_multiply.c get_multiply_ccin.c \
+	get_multiply_crin.c get_multiply_crinr.c get_multiply_noin.c \
+	get_multiply_rcin.c get_multiply_s.c get_neg.c get_none.c \
+	get_nonexistent.c get_null.c get_off64.c get_phase.c \
+	get_phase_affix.c get_polynom.c get_polynom_cmpin.c \
+	get_polynom_noin.c get_range.c get_recip.c get_recip_const.c \
+	get_recurse.c get_rofs.c get_sbit.c get_sf.c get_ss.c \
+	get_string.c get_type.c get_uint16.c get_uint32.c get_uint64.c \
+	get_window.c get_window_clr.c get_window_complex.c \
+	get_window_ge.c get_window_gt.c get_window_le.c \
+	get_window_lt.c get_window_ne.c get_window_s.c \
+	get_window_set.c get_zero.c get_zero_complex.c \
+	get_zero_float.c global_flags.c global_name.c global_ref.c \
+	global_ref_empty.c global_ref_set.c gzip_add.c gzip_del.c \
+	gzip_get.c gzip_get_far.c gzip_get_get.c gzip_get_get2.c \
+	gzip_get_put.c gzip_move_from.c gzip_move_to.c gzip_nframes.c \
+	gzip_put.c gzip_put_back.c gzip_put_endian.c gzip_put_get.c \
+	gzip_put_nframes.c gzip_put_off.c gzip_put_pad.c \
+	gzip_put_sub.c gzip_seek.c gzip_seek_far.c gzip_seek_put.c \
+	gzip_sync.c header_complex.c header_off64t.c hide.c hide_bad.c \
+	hide_hidden.c hide_hidden_bad.c hide_unhide.c \
+	hide_unhide_bad.c include_accmode.c include_affix.c \
+	include_auto.c include_cb.c include_creat.c include_ignore.c \
+	include_include.c include_index.c include_invalid.c \
+	include_nonexistent.c include_pc.c include_ref.c include_sub.c \
+	include_syntax.c index_domain.c index_index.c index_range.c \
+	index_s.c index_subset.c legacy_error.c legacy_estring.c \
+	legacy_format.c legacy_get.c legacy_get_put.c \
+	legacy_get_rofs.c legacy_nframes.c legacy_nonexistent.c \
+	legacy_put.c legacy_spf.c lzma_get.c lzma_nframes.c lzma_put.c \
+	lzma_xz_add.c lzma_xz_get.c lzma_xz_get_far.c \
+	lzma_xz_get_get.c lzma_xz_get_get2.c lzma_xz_get_put.c \
+	lzma_xz_move_to.c lzma_xz_nframes.c lzma_xz_put.c \
+	lzma_xz_put_back.c lzma_xz_put_endian.c lzma_xz_put_get.c \
+	lzma_xz_put_pad.c lzma_xz_seek.c lzma_xz_seek_far.c \
+	lzma_xz_sync.c madd.c madd_affix.c madd_alias.c \
+	madd_alias_affix.c madd_bit.c madd_bit_invalid.c madd_carray.c \
+	madd_clincom.c madd_const.c madd_cpolynom.c madd_crecip.c \
+	madd_crecip89.c madd_divide.c madd_index.c madd_lincom.c \
+	madd_lincom_invalid.c madd_linterp.c madd_linterp_invalid.c \
+	madd_mplex.c madd_multiply.c madd_multiply_invalid.c \
+	madd_phase.c madd_phase_invalid.c madd_polynom.c madd_recip.c \
+	madd_sbit.c madd_spec.c madd_spec_directive.c \
+	madd_spec_invalid.c madd_spec_resolv.c madd_string.c \
+	madd_window.c move_affix.c move_affix_dup.c move_affix_meta.c \
+	move_affix_updb.c move_alias.c move_data_enc_ar.c \
+	move_data_enc_ra.c move_data_endian.c move_data_foffs.c \
+	move_data_foffs_neg.c move_data_nop.c move_index.c move_meta.c \
+	move_move.c move_protect.c move_subdir.c name_affix.c \
+	name_affix_bad.c name_alias.c name_dangle.c name_dot5.c \
+	name_dot5r.c name_dot9.c name_dup.c name_meta.c name_move.c \
+	name_move_alias.c name_name.c name_updb.c name_updb_affix.c \
+	name_updb_alias.c name_updb_carray.c name_updb_const.c \
+	name_updb_const_alias.c native_bit.c native_const.c \
+	native_index.c native_lincom.c native_lincom_cmpin.c \
+	native_lincom_cmpscal.c native_linterp.c native_linterp_cmp.c \
+	native_mult.c native_mult1.c native_mult2.c native_phase.c \
+	native_polynom.c native_polynom_cmpin.c \
+	native_polynom_cmpscal.c native_raw.c native_recip.c \
+	native_recip_cmpin.c native_recip_cmpscal.c native_sbit.c \
+	native_string.c nentries_alias.c nentries_hidden.c \
+	nentries_noalias.c nentries_scalar.c nfields_hidden.c \
+	nfields_invalid.c nfields_nfields.c nfields_type.c \
+	nfields_type_hidden.c nfields_type_invalid.c nfields_vector.c \
+	nfields_vector_hidden.c nfields_vector_invalid.c nframes64.c \
+	nframes_empty.c nframes_invalid.c nframes_nframes.c \
+	nframes_off64.c nframes_spf.c nmeta.c nmeta_hidden.c \
+	nmeta_invalid.c nmeta_parent.c nmeta_type.c \
+	nmeta_type_hidden.c nmeta_type_invalid.c nmeta_type_parent.c \
+	nmeta_vectors.c nmeta_vectors_del.c nmeta_vectors_hidden.c \
 	nmeta_vectors_invalid.c nmeta_vectors_parent.c open_abs.c \
 	open_cb_abort.c open_cb_cont.c open_cb_ignore.c \
 	open_cb_invalid.c open_cb_rescan.c open_cb_rescan_alloc.c \
@@ -5928,35 +5941,35 @@ SOURCES = add_add.c add_affix.c add_alias.c add_alias_affix.c \
 	seek64.c seek_cur.c seek_end.c seek_far.c seek_foffs.c \
 	seek_foffs2.c seek_index.c seek_lincom.c seek_mult.c \
 	seek_neg.c seek_phase.c seek_range.c seek_range2.c seek_set.c \
-	seek_sub.c sie_get_big.c sie_get_little.c sie_move_from.c \
-	sie_move_to.c sie_nframes_big.c sie_nframes_little.c \
-	sie_put_append.c sie_put_append2.c sie_put_back.c \
-	sie_put_big.c sie_put_little.c sie_put_many.c sie_put_newo.c \
-	sie_put_newo0.c sie_put_pad.c sie_put_pad0.c sie_put_trunc.c \
-	sie_put_trunc2.c sie_put_trunc_nf.c sie_seek.c sie_seek_far.c \
-	sie_sync.c slim_get.c slim_nframes.c slim_seek.c \
-	slim_seek_far.c spf_alias.c spf_alias_meta.c \
-	spf_alias_missing.c spf_divide.c spf_lincom.c spf_multiply.c \
-	spf_polynom.c spf_raw.c spf_recip.c spf_recurse.c svlist.c \
-	svlist0.c svlist2.c svlist_hidden.c svlist_invalid.c \
-	svlist_meta.c svlist_meta0.c svlist_meta_hidden.c \
-	svlist_meta_invalid.c table.c table_code.c table_type.c tell.c \
-	tell64.c tell_multidiv.c tell_sub.c tok_arg.c tok_escape.c \
-	tok_quote.c trunc.c trunc_dir.c trunc_rdonly.c trunc_rofs.c \
-	trunc_truncsub.c unclude.c unclude_del.c unclude_move.c \
-	unclude_open.c version_0.c version_0_write.c version_1.c \
-	version_1_write.c version_2.c version_2_write.c version_3.c \
-	version_3_write.c version_4.c version_4_write.c version_5.c \
-	version_5_strict.c version_5_write.c version_6.c \
-	version_6_strict.c version_6_write.c version_7.c \
-	version_7_strict.c version_7_write.c version_8.c \
-	version_8_strict.c version_8_write.c version_9.c \
-	version_9_strict.c version_9_write.c vlist.c vlist_alias.c \
-	vlist_hidden.c vlist_invalid.c vlist_meta.c \
-	vlist_meta_hidden.c vlist_meta_invalid.c zzip_data.c \
-	zzip_get.c zzip_get_get.c zzip_nframes.c zzip_seek.c \
-	zzip_seek_far.c zzslim_get.c zzslim_nframes.c zzslim_seek.c \
-	zzslim_seek_far.c
+	seek_sub.c sie_get_big.c sie_get_header.c sie_get_little.c \
+	sie_move_from.c sie_move_to.c sie_nframes_big.c \
+	sie_nframes_little.c sie_put_append.c sie_put_append2.c \
+	sie_put_back.c sie_put_big.c sie_put_header.c sie_put_little.c \
+	sie_put_many.c sie_put_newo.c sie_put_newo0.c sie_put_pad.c \
+	sie_put_pad0.c sie_put_trunc.c sie_put_trunc2.c \
+	sie_put_trunc_nf.c sie_seek.c sie_seek_far.c sie_sync.c \
+	slim_get.c slim_nframes.c slim_seek.c slim_seek_far.c \
+	spf_alias.c spf_alias_meta.c spf_alias_missing.c spf_divide.c \
+	spf_lincom.c spf_multiply.c spf_polynom.c spf_raw.c \
+	spf_recip.c spf_recurse.c svlist.c svlist0.c svlist2.c \
+	svlist_hidden.c svlist_invalid.c svlist_meta.c svlist_meta0.c \
+	svlist_meta_hidden.c svlist_meta_invalid.c table.c \
+	table_code.c table_type.c tell.c tell64.c tell_multidiv.c \
+	tell_sub.c tok_arg.c tok_escape.c tok_quote.c trunc.c \
+	trunc_dir.c trunc_rdonly.c trunc_rofs.c trunc_truncsub.c \
+	unclude.c unclude_del.c unclude_move.c unclude_open.c \
+	version_0.c version_0_write.c version_1.c version_1_write.c \
+	version_2.c version_2_write.c version_3.c version_3_write.c \
+	version_4.c version_4_write.c version_5.c version_5_strict.c \
+	version_5_write.c version_6.c version_6_strict.c \
+	version_6_write.c version_7.c version_7_strict.c \
+	version_7_write.c version_8.c version_8_strict.c \
+	version_8_write.c version_9.c version_9_strict.c \
+	version_9_write.c vlist.c vlist_alias.c vlist_hidden.c \
+	vlist_invalid.c vlist_meta.c vlist_meta_hidden.c \
+	vlist_meta_invalid.c zzip_data.c zzip_get.c zzip_get_get.c \
+	zzip_nframes.c zzip_seek.c zzip_seek_far.c zzslim_get.c \
+	zzslim_nframes.c zzslim_seek.c zzslim_seek_far.c
 DIST_SOURCES = add_add.c add_affix.c add_alias.c add_alias_affix.c \
 	add_alias_meta.c add_amb_code7.c add_bit.c add_bit_bitnum.c \
 	add_bit_bitsize.c add_bit_invalid.c add_bit_numbits.c \
@@ -6140,80 +6153,80 @@ DIST_SOURCES = add_add.c add_affix.c add_alias.c add_alias_affix.c \
 	get_lincom_mdt.c get_lincom_noin.c get_lincom_non.c \
 	get_lincom_null.c get_lincom_spf.c get_linterp.c \
 	get_linterp1.c get_linterp_abs.c get_linterp_complex.c \
-	get_linterp_empty.c get_linterp_noin.c get_linterp_notab.c \
-	get_linterp_sort.c get_mplex.c get_mplex_bof.c \
-	get_mplex_complex.c get_mplex_lb.c get_mplex_lball.c \
-	get_mplex_nolb.c get_mplex_s.c get_mplex_saved.c \
-	get_multiply.c get_multiply_ccin.c get_multiply_crin.c \
-	get_multiply_crinr.c get_multiply_noin.c get_multiply_rcin.c \
-	get_multiply_s.c get_neg.c get_none.c get_nonexistent.c \
-	get_null.c get_off64.c get_phase.c get_phase_affix.c \
-	get_polynom.c get_polynom_cmpin.c get_polynom_noin.c \
-	get_range.c get_recip.c get_recip_const.c get_recurse.c \
-	get_rofs.c get_sbit.c get_sf.c get_ss.c get_string.c \
-	get_type.c get_uint16.c get_uint32.c get_uint64.c get_window.c \
-	get_window_clr.c get_window_complex.c get_window_ge.c \
-	get_window_gt.c get_window_le.c get_window_lt.c \
-	get_window_ne.c get_window_s.c get_window_set.c get_zero.c \
-	get_zero_complex.c get_zero_float.c global_flags.c \
-	global_name.c global_ref.c global_ref_empty.c global_ref_set.c \
-	gzip_add.c gzip_del.c gzip_get.c gzip_get_far.c gzip_get_get.c \
-	gzip_get_get2.c gzip_get_put.c gzip_move_from.c gzip_move_to.c \
-	gzip_nframes.c gzip_put.c gzip_put_back.c gzip_put_endian.c \
-	gzip_put_get.c gzip_put_nframes.c gzip_put_off.c \
-	gzip_put_pad.c gzip_put_sub.c gzip_seek.c gzip_seek_far.c \
-	gzip_seek_put.c gzip_sync.c header_complex.c header_off64t.c \
-	hide.c hide_bad.c hide_hidden.c hide_hidden_bad.c \
-	hide_unhide.c hide_unhide_bad.c include_accmode.c \
-	include_affix.c include_auto.c include_cb.c include_creat.c \
-	include_ignore.c include_include.c include_index.c \
-	include_invalid.c include_nonexistent.c include_pc.c \
-	include_ref.c include_sub.c include_syntax.c index_domain.c \
-	index_index.c index_range.c index_s.c index_subset.c \
-	legacy_error.c legacy_estring.c legacy_format.c legacy_get.c \
-	legacy_get_put.c legacy_get_rofs.c legacy_nframes.c \
-	legacy_nonexistent.c legacy_put.c legacy_spf.c lzma_get.c \
-	lzma_nframes.c lzma_put.c lzma_xz_add.c lzma_xz_get.c \
-	lzma_xz_get_far.c lzma_xz_get_get.c lzma_xz_get_get2.c \
-	lzma_xz_get_put.c lzma_xz_move_to.c lzma_xz_nframes.c \
-	lzma_xz_put.c lzma_xz_put_back.c lzma_xz_put_endian.c \
-	lzma_xz_put_get.c lzma_xz_put_pad.c lzma_xz_seek.c \
-	lzma_xz_seek_far.c lzma_xz_sync.c madd.c madd_affix.c \
-	madd_alias.c madd_alias_affix.c madd_bit.c madd_bit_invalid.c \
-	madd_carray.c madd_clincom.c madd_const.c madd_cpolynom.c \
-	madd_crecip.c madd_crecip89.c madd_divide.c madd_index.c \
-	madd_lincom.c madd_lincom_invalid.c madd_linterp.c \
-	madd_linterp_invalid.c madd_mplex.c madd_multiply.c \
-	madd_multiply_invalid.c madd_phase.c madd_phase_invalid.c \
-	madd_polynom.c madd_recip.c madd_sbit.c madd_spec.c \
-	madd_spec_directive.c madd_spec_invalid.c madd_spec_resolv.c \
-	madd_string.c madd_window.c move_affix.c move_affix_dup.c \
-	move_affix_meta.c move_affix_updb.c move_alias.c \
-	move_data_enc_ar.c move_data_enc_ra.c move_data_endian.c \
-	move_data_foffs.c move_data_foffs_neg.c move_data_nop.c \
-	move_index.c move_meta.c move_move.c move_protect.c \
-	move_subdir.c name_affix.c name_affix_bad.c name_alias.c \
-	name_dangle.c name_dot5.c name_dot5r.c name_dot9.c name_dup.c \
-	name_meta.c name_move.c name_move_alias.c name_name.c \
-	name_updb.c name_updb_affix.c name_updb_alias.c \
-	name_updb_carray.c name_updb_const.c name_updb_const_alias.c \
-	native_bit.c native_const.c native_index.c native_lincom.c \
-	native_lincom_cmpin.c native_lincom_cmpscal.c native_linterp.c \
-	native_linterp_cmp.c native_mult.c native_mult1.c \
-	native_mult2.c native_phase.c native_polynom.c \
-	native_polynom_cmpin.c native_polynom_cmpscal.c native_raw.c \
-	native_recip.c native_recip_cmpin.c native_recip_cmpscal.c \
-	native_sbit.c native_string.c nentries_alias.c \
-	nentries_hidden.c nentries_noalias.c nentries_scalar.c \
-	nfields_hidden.c nfields_invalid.c nfields_nfields.c \
-	nfields_type.c nfields_type_hidden.c nfields_type_invalid.c \
-	nfields_vector.c nfields_vector_hidden.c \
-	nfields_vector_invalid.c nframes64.c nframes_empty.c \
-	nframes_invalid.c nframes_nframes.c nframes_off64.c \
-	nframes_spf.c nmeta.c nmeta_hidden.c nmeta_invalid.c \
-	nmeta_parent.c nmeta_type.c nmeta_type_hidden.c \
-	nmeta_type_invalid.c nmeta_type_parent.c nmeta_vectors.c \
-	nmeta_vectors_del.c nmeta_vectors_hidden.c \
+	get_linterp_empty.c get_linterp_nodir.c get_linterp_noin.c \
+	get_linterp_notab.c get_linterp_sort.c get_mplex.c \
+	get_mplex_bof.c get_mplex_complex.c get_mplex_lb.c \
+	get_mplex_lball.c get_mplex_nolb.c get_mplex_s.c \
+	get_mplex_saved.c get_multiply.c get_multiply_ccin.c \
+	get_multiply_crin.c get_multiply_crinr.c get_multiply_noin.c \
+	get_multiply_rcin.c get_multiply_s.c get_neg.c get_none.c \
+	get_nonexistent.c get_null.c get_off64.c get_phase.c \
+	get_phase_affix.c get_polynom.c get_polynom_cmpin.c \
+	get_polynom_noin.c get_range.c get_recip.c get_recip_const.c \
+	get_recurse.c get_rofs.c get_sbit.c get_sf.c get_ss.c \
+	get_string.c get_type.c get_uint16.c get_uint32.c get_uint64.c \
+	get_window.c get_window_clr.c get_window_complex.c \
+	get_window_ge.c get_window_gt.c get_window_le.c \
+	get_window_lt.c get_window_ne.c get_window_s.c \
+	get_window_set.c get_zero.c get_zero_complex.c \
+	get_zero_float.c global_flags.c global_name.c global_ref.c \
+	global_ref_empty.c global_ref_set.c gzip_add.c gzip_del.c \
+	gzip_get.c gzip_get_far.c gzip_get_get.c gzip_get_get2.c \
+	gzip_get_put.c gzip_move_from.c gzip_move_to.c gzip_nframes.c \
+	gzip_put.c gzip_put_back.c gzip_put_endian.c gzip_put_get.c \
+	gzip_put_nframes.c gzip_put_off.c gzip_put_pad.c \
+	gzip_put_sub.c gzip_seek.c gzip_seek_far.c gzip_seek_put.c \
+	gzip_sync.c header_complex.c header_off64t.c hide.c hide_bad.c \
+	hide_hidden.c hide_hidden_bad.c hide_unhide.c \
+	hide_unhide_bad.c include_accmode.c include_affix.c \
+	include_auto.c include_cb.c include_creat.c include_ignore.c \
+	include_include.c include_index.c include_invalid.c \
+	include_nonexistent.c include_pc.c include_ref.c include_sub.c \
+	include_syntax.c index_domain.c index_index.c index_range.c \
+	index_s.c index_subset.c legacy_error.c legacy_estring.c \
+	legacy_format.c legacy_get.c legacy_get_put.c \
+	legacy_get_rofs.c legacy_nframes.c legacy_nonexistent.c \
+	legacy_put.c legacy_spf.c lzma_get.c lzma_nframes.c lzma_put.c \
+	lzma_xz_add.c lzma_xz_get.c lzma_xz_get_far.c \
+	lzma_xz_get_get.c lzma_xz_get_get2.c lzma_xz_get_put.c \
+	lzma_xz_move_to.c lzma_xz_nframes.c lzma_xz_put.c \
+	lzma_xz_put_back.c lzma_xz_put_endian.c lzma_xz_put_get.c \
+	lzma_xz_put_pad.c lzma_xz_seek.c lzma_xz_seek_far.c \
+	lzma_xz_sync.c madd.c madd_affix.c madd_alias.c \
+	madd_alias_affix.c madd_bit.c madd_bit_invalid.c madd_carray.c \
+	madd_clincom.c madd_const.c madd_cpolynom.c madd_crecip.c \
+	madd_crecip89.c madd_divide.c madd_index.c madd_lincom.c \
+	madd_lincom_invalid.c madd_linterp.c madd_linterp_invalid.c \
+	madd_mplex.c madd_multiply.c madd_multiply_invalid.c \
+	madd_phase.c madd_phase_invalid.c madd_polynom.c madd_recip.c \
+	madd_sbit.c madd_spec.c madd_spec_directive.c \
+	madd_spec_invalid.c madd_spec_resolv.c madd_string.c \
+	madd_window.c move_affix.c move_affix_dup.c move_affix_meta.c \
+	move_affix_updb.c move_alias.c move_data_enc_ar.c \
+	move_data_enc_ra.c move_data_endian.c move_data_foffs.c \
+	move_data_foffs_neg.c move_data_nop.c move_index.c move_meta.c \
+	move_move.c move_protect.c move_subdir.c name_affix.c \
+	name_affix_bad.c name_alias.c name_dangle.c name_dot5.c \
+	name_dot5r.c name_dot9.c name_dup.c name_meta.c name_move.c \
+	name_move_alias.c name_name.c name_updb.c name_updb_affix.c \
+	name_updb_alias.c name_updb_carray.c name_updb_const.c \
+	name_updb_const_alias.c native_bit.c native_const.c \
+	native_index.c native_lincom.c native_lincom_cmpin.c \
+	native_lincom_cmpscal.c native_linterp.c native_linterp_cmp.c \
+	native_mult.c native_mult1.c native_mult2.c native_phase.c \
+	native_polynom.c native_polynom_cmpin.c \
+	native_polynom_cmpscal.c native_raw.c native_recip.c \
+	native_recip_cmpin.c native_recip_cmpscal.c native_sbit.c \
+	native_string.c nentries_alias.c nentries_hidden.c \
+	nentries_noalias.c nentries_scalar.c nfields_hidden.c \
+	nfields_invalid.c nfields_nfields.c nfields_type.c \
+	nfields_type_hidden.c nfields_type_invalid.c nfields_vector.c \
+	nfields_vector_hidden.c nfields_vector_invalid.c nframes64.c \
+	nframes_empty.c nframes_invalid.c nframes_nframes.c \
+	nframes_off64.c nframes_spf.c nmeta.c nmeta_hidden.c \
+	nmeta_invalid.c nmeta_parent.c nmeta_type.c \
+	nmeta_type_hidden.c nmeta_type_invalid.c nmeta_type_parent.c \
+	nmeta_vectors.c nmeta_vectors_del.c nmeta_vectors_hidden.c \
 	nmeta_vectors_invalid.c nmeta_vectors_parent.c open_abs.c \
 	open_cb_abort.c open_cb_cont.c open_cb_ignore.c \
 	open_cb_invalid.c open_cb_rescan.c open_cb_rescan_alloc.c \
@@ -6307,35 +6320,35 @@ DIST_SOURCES = add_add.c add_affix.c add_alias.c add_alias_affix.c \
 	seek64.c seek_cur.c seek_end.c seek_far.c seek_foffs.c \
 	seek_foffs2.c seek_index.c seek_lincom.c seek_mult.c \
 	seek_neg.c seek_phase.c seek_range.c seek_range2.c seek_set.c \
-	seek_sub.c sie_get_big.c sie_get_little.c sie_move_from.c \
-	sie_move_to.c sie_nframes_big.c sie_nframes_little.c \
-	sie_put_append.c sie_put_append2.c sie_put_back.c \
-	sie_put_big.c sie_put_little.c sie_put_many.c sie_put_newo.c \
-	sie_put_newo0.c sie_put_pad.c sie_put_pad0.c sie_put_trunc.c \
-	sie_put_trunc2.c sie_put_trunc_nf.c sie_seek.c sie_seek_far.c \
-	sie_sync.c slim_get.c slim_nframes.c slim_seek.c \
-	slim_seek_far.c spf_alias.c spf_alias_meta.c \
-	spf_alias_missing.c spf_divide.c spf_lincom.c spf_multiply.c \
-	spf_polynom.c spf_raw.c spf_recip.c spf_recurse.c svlist.c \
-	svlist0.c svlist2.c svlist_hidden.c svlist_invalid.c \
-	svlist_meta.c svlist_meta0.c svlist_meta_hidden.c \
-	svlist_meta_invalid.c table.c table_code.c table_type.c tell.c \
-	tell64.c tell_multidiv.c tell_sub.c tok_arg.c tok_escape.c \
-	tok_quote.c trunc.c trunc_dir.c trunc_rdonly.c trunc_rofs.c \
-	trunc_truncsub.c unclude.c unclude_del.c unclude_move.c \
-	unclude_open.c version_0.c version_0_write.c version_1.c \
-	version_1_write.c version_2.c version_2_write.c version_3.c \
-	version_3_write.c version_4.c version_4_write.c version_5.c \
-	version_5_strict.c version_5_write.c version_6.c \
-	version_6_strict.c version_6_write.c version_7.c \
-	version_7_strict.c version_7_write.c version_8.c \
-	version_8_strict.c version_8_write.c version_9.c \
-	version_9_strict.c version_9_write.c vlist.c vlist_alias.c \
-	vlist_hidden.c vlist_invalid.c vlist_meta.c \
-	vlist_meta_hidden.c vlist_meta_invalid.c zzip_data.c \
-	zzip_get.c zzip_get_get.c zzip_nframes.c zzip_seek.c \
-	zzip_seek_far.c zzslim_get.c zzslim_nframes.c zzslim_seek.c \
-	zzslim_seek_far.c
+	seek_sub.c sie_get_big.c sie_get_header.c sie_get_little.c \
+	sie_move_from.c sie_move_to.c sie_nframes_big.c \
+	sie_nframes_little.c sie_put_append.c sie_put_append2.c \
+	sie_put_back.c sie_put_big.c sie_put_header.c sie_put_little.c \
+	sie_put_many.c sie_put_newo.c sie_put_newo0.c sie_put_pad.c \
+	sie_put_pad0.c sie_put_trunc.c sie_put_trunc2.c \
+	sie_put_trunc_nf.c sie_seek.c sie_seek_far.c sie_sync.c \
+	slim_get.c slim_nframes.c slim_seek.c slim_seek_far.c \
+	spf_alias.c spf_alias_meta.c spf_alias_missing.c spf_divide.c \
+	spf_lincom.c spf_multiply.c spf_polynom.c spf_raw.c \
+	spf_recip.c spf_recurse.c svlist.c svlist0.c svlist2.c \
+	svlist_hidden.c svlist_invalid.c svlist_meta.c svlist_meta0.c \
+	svlist_meta_hidden.c svlist_meta_invalid.c table.c \
+	table_code.c table_type.c tell.c tell64.c tell_multidiv.c \
+	tell_sub.c tok_arg.c tok_escape.c tok_quote.c trunc.c \
+	trunc_dir.c trunc_rdonly.c trunc_rofs.c trunc_truncsub.c \
+	unclude.c unclude_del.c unclude_move.c unclude_open.c \
+	version_0.c version_0_write.c version_1.c version_1_write.c \
+	version_2.c version_2_write.c version_3.c version_3_write.c \
+	version_4.c version_4_write.c version_5.c version_5_strict.c \
+	version_5_write.c version_6.c version_6_strict.c \
+	version_6_write.c version_7.c version_7_strict.c \
+	version_7_write.c version_8.c version_8_strict.c \
+	version_8_write.c version_9.c version_9_strict.c \
+	version_9_write.c vlist.c vlist_alias.c vlist_hidden.c \
+	vlist_invalid.c vlist_meta.c vlist_meta_hidden.c \
+	vlist_meta_invalid.c zzip_data.c zzip_get.c zzip_get_get.c \
+	zzip_nframes.c zzip_seek.c zzip_seek_far.c zzslim_get.c \
+	zzslim_nframes.c zzslim_seek.c zzslim_seek_far.c
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -6520,6 +6533,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -6569,6 +6583,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@
@@ -6610,7 +6625,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
-# Copyright (C) 2008-2015 D. V. Wiebe
+# Copyright (C) 2008-2016 D. V. Wiebe
 #
 ##########################################################################
 #
@@ -6805,18 +6820,19 @@ GET_TESTS = get64 get_affix get_bad_code get_bit get_carray get_carray_len \
 					get_lincom3 get_lincom3s get_lincom_mdt get_lincom_noin \
 					get_lincom_non get_lincom_null get_lincom_spf get_linterp \
 					get_linterp1 get_linterp_abs get_linterp_complex get_linterp_empty \
-					get_linterp_noin get_linterp_notab get_linterp_sort get_mplex \
-					get_mplex_bof get_mplex_complex get_mplex_lb get_mplex_lball \
-					get_mplex_nolb get_mplex_s get_mplex_saved get_multiply \
-					get_multiply_ccin get_multiply_crin get_multiply_crinr \
-					get_multiply_noin get_multiply_rcin get_multiply_s get_neg get_none \
-					get_nonexistent get_null get_off64 get_phase get_phase_affix \
-					get_polynom get_polynom_cmpin get_polynom_noin get_range get_recip \
-					get_recip_const get_recurse get_rofs get_sbit get_sf get_ss \
-					get_string get_type get_uint16 get_uint32 get_uint64 get_window \
-					get_window_clr get_window_complex get_window_ge get_window_gt \
-					get_window_le get_window_lt get_window_ne get_window_s \
-					get_window_set get_zero get_zero_complex get_zero_float
+					get_linterp_nodir get_linterp_noin get_linterp_notab \
+					get_linterp_sort get_mplex get_mplex_bof get_mplex_complex \
+					get_mplex_lb get_mplex_lball get_mplex_nolb get_mplex_s \
+					get_mplex_saved get_multiply get_multiply_ccin get_multiply_crin \
+					get_multiply_crinr get_multiply_noin get_multiply_rcin \
+					get_multiply_s get_neg get_none get_nonexistent get_null get_off64 \
+					get_phase get_phase_affix get_polynom get_polynom_cmpin \
+					get_polynom_noin get_range get_recip get_recip_const get_recurse \
+					get_rofs get_sbit get_sf get_ss get_string get_type get_uint16 \
+					get_uint32 get_uint64 get_window get_window_clr get_window_complex \
+					get_window_ge get_window_gt get_window_le get_window_lt \
+					get_window_ne get_window_s get_window_set get_zero get_zero_complex \
+					get_zero_float
 
 GLOBAL_TESTS = global_flags global_name global_ref global_ref_empty global_ref_set
 GZIP_TESTS = gzip_add gzip_del gzip_get gzip_get_far gzip_get_get gzip_get_get2 \
@@ -6966,11 +6982,11 @@ SEEK_TESTS = seek64 seek_cur seek_end seek_far seek_foffs seek_foffs2 seek_index
 					 seek_lincom seek_mult seek_neg seek_phase seek_range seek_range2 \
 					 seek_set seek_sub
 
-SIE_TESTS = sie_get_big sie_get_little sie_move_from sie_move_to sie_nframes_big \
-					sie_nframes_little sie_put_append sie_put_append2 sie_put_back \
-					sie_put_big sie_put_little sie_put_many sie_put_newo sie_put_newo0 \
-					sie_put_pad sie_put_pad0 sie_put_trunc sie_put_trunc2 \
-					sie_put_trunc_nf sie_seek sie_seek_far sie_sync
+SIE_TESTS = sie_get_big sie_get_header sie_get_little sie_move_from sie_move_to \
+					sie_nframes_big sie_nframes_little sie_put_append sie_put_append2 \
+					sie_put_back sie_put_big sie_put_header sie_put_little sie_put_many \
+					sie_put_newo sie_put_newo0 sie_put_pad sie_put_pad0 sie_put_trunc \
+					sie_put_trunc2 sie_put_trunc_nf sie_seek sie_seek_far sie_sync
 
 SLIM_TESTS = slim_get slim_nframes slim_seek slim_seek_far
 SVLIST_TESTS = svlist svlist0 svlist2 svlist_hidden svlist_invalid svlist_meta \
@@ -9183,6 +9199,10 @@ get_linterp_empty$(EXEEXT): $(get_linterp_empty_OBJECTS) $(get_linterp_empty_DEP
 	@rm -f get_linterp_empty$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(get_linterp_empty_OBJECTS) $(get_linterp_empty_LDADD) $(LIBS)
 
+get_linterp_nodir$(EXEEXT): $(get_linterp_nodir_OBJECTS) $(get_linterp_nodir_DEPENDENCIES) $(EXTRA_get_linterp_nodir_DEPENDENCIES) 
+	@rm -f get_linterp_nodir$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(get_linterp_nodir_OBJECTS) $(get_linterp_nodir_LDADD) $(LIBS)
+
 get_linterp_noin$(EXEEXT): $(get_linterp_noin_OBJECTS) $(get_linterp_noin_DEPENDENCIES) $(EXTRA_get_linterp_noin_DEPENDENCIES) 
 	@rm -f get_linterp_noin$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(get_linterp_noin_OBJECTS) $(get_linterp_noin_LDADD) $(LIBS)
@@ -11379,6 +11399,10 @@ sie_get_big$(EXEEXT): $(sie_get_big_OBJECTS) $(sie_get_big_DEPENDENCIES) $(EXTRA
 	@rm -f sie_get_big$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(sie_get_big_OBJECTS) $(sie_get_big_LDADD) $(LIBS)
 
+sie_get_header$(EXEEXT): $(sie_get_header_OBJECTS) $(sie_get_header_DEPENDENCIES) $(EXTRA_sie_get_header_DEPENDENCIES) 
+	@rm -f sie_get_header$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(sie_get_header_OBJECTS) $(sie_get_header_LDADD) $(LIBS)
+
 sie_get_little$(EXEEXT): $(sie_get_little_OBJECTS) $(sie_get_little_DEPENDENCIES) $(EXTRA_sie_get_little_DEPENDENCIES) 
 	@rm -f sie_get_little$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(sie_get_little_OBJECTS) $(sie_get_little_LDADD) $(LIBS)
@@ -11415,6 +11439,10 @@ sie_put_big$(EXEEXT): $(sie_put_big_OBJECTS) $(sie_put_big_DEPENDENCIES) $(EXTRA
 	@rm -f sie_put_big$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(sie_put_big_OBJECTS) $(sie_put_big_LDADD) $(LIBS)
 
+sie_put_header$(EXEEXT): $(sie_put_header_OBJECTS) $(sie_put_header_DEPENDENCIES) $(EXTRA_sie_put_header_DEPENDENCIES) 
+	@rm -f sie_put_header$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(sie_put_header_OBJECTS) $(sie_put_header_LDADD) $(LIBS)
+
 sie_put_little$(EXEEXT): $(sie_put_little_OBJECTS) $(sie_put_little_DEPENDENCIES) $(EXTRA_sie_put_little_DEPENDENCIES) 
 	@rm -f sie_put_little$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(sie_put_little_OBJECTS) $(sie_put_little_LDADD) $(LIBS)
@@ -12341,6 +12369,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_abs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_complex.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_empty.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_nodir.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_noin.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_notab.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/get_linterp_sort.Po at am__quote@
@@ -12890,6 +12919,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/seek_set.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/seek_sub.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_get_big.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_get_header.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_get_little.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_move_from.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_move_to.Po at am__quote@
@@ -12899,6 +12929,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_append2.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_back.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_big.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_header.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_little.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_many.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sie_put_newo.Po at am__quote@
diff --git a/test/del_bad_code.c b/test/del_bad_code.c
index 1595d4e..12cef07 100644
--- a/test/del_bad_code.c
+++ b/test/del_bad_code.c
@@ -24,7 +24,7 @@ int main(void)
 {
   const char *filedir = "dirfile";
   const char *format = "dirfile/format";
-  int fd, h1, e1, r = 0;
+  int h1, e1, r = 0;
   DIRFILE *D;
 
   rmdirfile();
diff --git a/test/del_bad_code.c b/test/get_linterp_nodir.c
similarity index 57%
copy from test/del_bad_code.c
copy to test/get_linterp_nodir.c
index 1595d4e..706bb0b 100644
--- a/test/del_bad_code.c
+++ b/test/get_linterp_nodir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 D. V. Wiebe
+/* Copyright (C) 2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -24,19 +24,40 @@ int main(void)
 {
   const char *filedir = "dirfile";
   const char *format = "dirfile/format";
-  int fd, h1, e1, r = 0;
+  const char *data = "dirfile/data";
+  const char *table = "dirfile/table";
+  const char *format_data =
+    "linterp LINTERP data ./somewhere/table\n"
+    "data RAW UINT8 1\n";
+  unsigned char data_data[64];
+  int fd, n, error, r = 0;
   DIRFILE *D;
 
   rmdirfile();
+  mkdir(filedir, 0777);
 
-  D = gd_open(filedir, GD_RDWR | GD_CREAT | GD_EXCL);
-  h1 = gd_delete(D, "something", 0);
-  e1 = gd_error(D);
+  for (fd = 0; fd < 64; ++fd)
+    data_data[fd] = (unsigned char)fd;
 
-  CHECKI(e1, GD_E_BAD_CODE);
-  CHECKI(h1, -1);
+  fd = open(format, O_CREAT | O_EXCL | O_WRONLY, 0666);
+  write(fd, format_data, strlen(format_data));
+  close(fd);
+
+  fd = open(data, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0666);
+  write(fd, data_data, 64);
+  close(fd);
+
+  D = gd_open(filedir, GD_RDONLY);
+  n = gd_getdata(D, "linterp", 5, 0, 1, 0, GD_NULL, NULL);
+  error = gd_error(D);
+
+  CHECKI(error, GD_E_IO);
+  CHECKI(n, 0);
 
   gd_discard(D);
+
+  unlink(table);
+  unlink(data);
   unlink(format);
   rmdir(filedir);
 
diff --git a/test/del_bad_code.c b/test/sie_get_header.c
similarity index 50%
copy from test/del_bad_code.c
copy to test/sie_get_header.c
index 1595d4e..7c6ce0d 100644
--- a/test/del_bad_code.c
+++ b/test/sie_get_header.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 D. V. Wiebe
+/* Copyright (C) 2016 D. V. Wiebe
  *
  ***************************************************************************
  *
@@ -20,25 +20,51 @@
  */
 #include "test.h"
 
+#include <stdlib.h>
+
 int main(void)
 {
   const char *filedir = "dirfile";
   const char *format = "dirfile/format";
-  int fd, h1, e1, r = 0;
+  const char *data = "dirfile/data.sie";
+  const char *format_data = "data RAW UINT16 8\n/ENCODING sie\n/ENDIAN big\n";
+  uint16_t c[16];
+  const uint8_t data_data[] = {
+    /* Header */
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82,
+    /* Data */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0x22,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x33, 0x33,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x44, 0x44
+  };
   DIRFILE *D;
+  int fd, i, n, error, r = 0;
 
   rmdirfile();
+  mkdir(filedir, 0777); 
+
+  fd = open(format, O_CREAT | O_EXCL | O_WRONLY, 0666);
+  write(fd, format_data, strlen(format_data));
+  close(fd);
 
-  D = gd_open(filedir, GD_RDWR | GD_CREAT | GD_EXCL);
-  h1 = gd_delete(D, "something", 0);
-  e1 = gd_error(D);
+  fd = open(data, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0666);
+  write(fd, data_data, sizeof(data_data));
+  close(fd);
 
-  CHECKI(e1, GD_E_BAD_CODE);
-  CHECKI(h1, -1);
+  D = gd_open(filedir, GD_RDONLY | GD_VERBOSE);
+  n = gd_getdata(D, "data", 3, 0, 2, 0, GD_UINT16, c);
+  error = gd_error(D);
 
   gd_discard(D);
+
+  unlink(data);
   unlink(format);
   rmdir(filedir);
 
+  CHECKI(error, 0);
+  CHECKI(n, 16);
+  for (i = 0; i < 16; ++i)
+    CHECKXi(i,c[i], (i <= 8) ? 0x3333 : 0x4444);
+
   return r;
 }
diff --git a/test/sie_put_header.c b/test/sie_put_header.c
new file mode 100644
index 0000000..8899ed3
--- /dev/null
+++ b/test/sie_put_header.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2011, 2013, 2016 D. V. Wiebe
+ *
+ ***************************************************************************
+ *
+ * This file is part of the GetData project.
+ *
+ * GetData 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.
+ *
+ * GetData 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 GetData; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "test.h"
+
+#include <stdlib.h>
+
+int main(void)
+{
+  const char *filedir = "dirfile";
+  const char *format = "dirfile/format";
+  const char *data = "dirfile/data.sie";
+  const char *format_data = "data RAW UINT8 8\n/ENCODING sie\n/ENDIAN big\n";
+  unsigned char c[16] = {
+    0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34, 0x34,
+    0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
+  };
+  const uint8_t data_data[] = {
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x12,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x22,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x32
+  };
+#define NREC (4 + 1)
+  const uint8_t data_out[] = {
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x12,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x23,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x34,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x32
+  };
+  uint8_t check[(NREC + 1) * 9];
+  DIRFILE *D;
+  int fd, i, n, error, r = 0;
+  ssize_t s;
+
+  rmdirfile();
+  mkdir(filedir, 0777); 
+
+  fd = open(format, O_CREAT | O_EXCL | O_WRONLY, 0666);
+  write(fd, format_data, strlen(format_data));
+  close(fd);
+
+  fd = open(data, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0666);
+  write(fd, data_data, sizeof(data_data));
+  close(fd);
+
+  D = gd_open(filedir, GD_RDWR | GD_VERBOSE);
+  n = gd_putdata(D, "data", 0, 0x11, 2, 0, GD_UINT8, c);
+  error = gd_error(D);
+
+  CHECKI(error, 0);
+  CHECKI(n, 16);
+
+  gd_discard(D);
+
+  fd = open(data, O_RDONLY | O_BINARY);
+  s = read(fd, check, (NREC + 1) * 9);
+  close(fd);
+  CHECKI(s, NREC * 9);
+
+  unlink(data);
+  unlink(format);
+  rmdir(filedir);
+
+  for (i = 0; i < NREC * 9; ++i)
+    CHECKXi(i, check[i], data_out[i]);
+
+  return r;
+}
diff --git a/util/Makefile.in b/util/Makefile.in
index 0d4c35c..bc4e820 100644
--- a/util/Makefile.in
+++ b/util/Makefile.in
@@ -320,6 +320,7 @@ PHP_libs = @PHP_libs@
 PRINTF = @PRINTF@
 PRIVATE_LIBS = @PRIVATE_LIBS@
 PYTHON = @PYTHON@
+PYTHON_OBJECT_SUFFIX = @PYTHON_OBJECT_SUFFIX@
 PYTHON_PLATFORM = @PYTHON_PLATFORM@
 PYTHON_VERSION = @PYTHON_VERSION@
 RANLIB = @RANLIB@
@@ -369,6 +370,7 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
 htmldir = @htmldir@
+idl_prefix = @idl_prefix@
 idldir = @idldir@
 includedir = @includedir@
 infodir = @infodir@

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/libgetdata.git



More information about the debian-science-commits mailing list